/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.nina;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.morilib.automata.DFA;
import net.morilib.automata.NFA;
import net.morilib.automata.NFAState;
import net.morilib.automata.dfa.ConvertedRangeDFA;
import net.morilib.automata.nfa.RegexParseException;
import net.morilib.automata.nfa.RegexpParser;
import net.morilib.nina.lib.NinaLibrary;
import net.morilib.range.CharSets;

public class NinaParser {

	//
	static class Z {

		Object vertex, edge;

		Z(Object v, Object e) {
			vertex = v;
			edge   = e;
		}

	}

	//
	private static enum S {
		INIT,  PRAG0, PRAG,  LICN1,
		PACK,  MACHN, TYPE,  TYP2,  TYP3,
		OPTN,  OPTV,  OPTQ,  ALIAS, ALI_V, ALI_Q,
		PLB_1, PLB_2, PDF_1, PDF_2, PDF_3, REQ1,  REQ2, VTYP1,
		COMNT,
		DEF1,  DEF2,  DEF3,  DEF4,  DEFI1, DEFI2,
		LINIT, LINI2, FI_L0, FI_L1, FI_L2, FI_L3, FI_L4,
		FI_E,  FI_E2, FI_S,  FI_S2, FI_W,  FI_W2, FI_N,
		LQUOT, LCSET, LGNFA, LSNFA,
		PRI01, PRI02, PRI03, PRI04,
		LPRI1, LPRI2,
		LBLE,  FL_S,  FL_W,  FL_N,  FL_E,
		FMNW,  FMNW2, FM_E,  FMNE,  FMNE2, FM_S,
		FMSE,  FMSE2, FM_W,  FMSW,  FMSW2, FM_N,
		FRNW,  FRNW2, FR_E,  FRNE,  FRNE2, FR_S,
		FRSE,  FRSE2, FR_W,  FRSW,  FRSW2, FR_N,
		AR_N,  AR_E,  AREN0, AREN1, AR_EQ, AR_Eq, ARED1, ARED2,
		AR_ER, ARER1, ARER2, ARER3, ARER4,
		AR_EI, AR_Ei, AR_EG, AR_Eg, AR_ES, AR_EM, AR_EX, AREE1, AREE2,
		AR_S,  AR_W,  ARWN0, ARWN1, ARWN2, AR_WQ,
		AR_Wq, AR_Wy, AR_Wn, AR_Wr, AR_Wt, AR_W0, ARWD1, ARWD2,
		AR_WR, ARWR1, ARWR2, ARWR3, ARWR4, ARWR5,
		AR_WI, AR_Wi, ARWi2, AR_WG, AR_Wg, AR_WS, AR_WM, AR_WX,
		AR_ZN, AR_ZS, AR_ZE, AR_ZW,
		F2_W,  F2_N,  F3_W,  F3_N,
		BR_N,  BR_E,  BR_S,  BR_W,
		BR2_N, BR2_E, BR2_S, BR2_W,
		FRR_S, FRR_E, FRR_N, FRR_W,
		DED01, DED02, DED03, DED04, DED05, DED06,
		ARR_N, ARR_E, ARR_S, ARR_W,
		ARRZN, ARRZS, ARRZE, ARRZW,
		WP_E1, WP_W1,
		TOIX1, TOJX1, TOIx1, TOIY1, SER1E, RETP1,
		TORY1, SER11, SER1q, SER1c, SER1r, SER1b,
		SER1F, SER1G, SER1H,
		SER1W, SER1Q, SER1C, SER1R, SER1B,
		SER1X, SER1Y,
		WP_E2, WP_W2,
		TOIX2, TOIY2,
		SER2E, SER2F, SER2G, SER2H, SER2W, SER2X, SER2Y,
		ONS_0, ONS_N, ONS_E, ONS_S, ONS_W,
		ONS_n, ONS_e, ONS_s, ONS_w
	}

	//
	private static final Pattern ANYS = Pattern.compile("\\.([0-9]+)");
	private static final Pattern CHSS = Pattern.compile(
			"\\[(.*)\\]([0-9]+)");
	private static final Pattern REPS = Pattern.compile(
			"([^\\+]*)\\+(.*)");
	private static final Pattern LB_Q = Pattern.compile("'(.*)'");
	private static final Pattern LB_D = Pattern.compile("\"(.*)\"");
	private static final Pattern LB_S = Pattern.compile("\\[(.*)\\]");
	private static final Pattern LB_R = Pattern.compile("`(.*)`");
	private static final Pattern LB_L = Pattern.compile("\\$\\{(.*)\\}");
	private static final Pattern LD_H = Pattern.compile(
			"0x([0-9A-Fa-f]{1,4})");
	private static final Pattern LD_O = Pattern.compile(
			"01?[0-7]{1,5}");
	private static final Pattern LD_D = Pattern.compile("[0-9]+");
	private static final Pattern DIGI = Pattern.compile(
			":(signed-)?digits-([1-8*])");
	private static final Pattern DIGH = Pattern.compile(
			":hex-(8|16|32|\\*)");
	private static final Pattern DIGO = Pattern.compile(
			":oct-(8|16|32|\\*)");
	private static final Pattern INDT = Pattern.compile(
			":indent(<=?|>=?|==|!=)([\\+\\-][0-9]+)?");
	private static final String  FLOT = ":float";
	private static final String  IJAV = ":identifier-Java";
	private static final String  ID_C = ":identifier-C";

	//
	private static final String NL = System.getProperty(
			"line.separator");

	//
	static final String STARTSYM = "S";
	static final String DEADSYM  = "D";
	static final int _PAUSE = 1;
	static final int _PRINT = 2;
	static final Object _FRAME1 = Character.valueOf('x');
	static final Object _FRAME2 = Character.valueOf('X');

	//
	private Map<String, String> pragmas =
			new HashMap<String, String>();
	private Quadro q;
	private S etat = S.INIT;

	//
	Map<String, String> params = new HashMap<String, String>();
	NinaSubautomata subfas;
	private List<String> libs = Collections.emptyList();
	private StringBuffer buf = new StringBuffer();
	private StringBuffer bf2 = new StringBuffer();
	private StringWriter defs;
	private PrintWriter  def;
	private Class<?> type = Character.TYPE;
	private NinaAction action;
	private NinaConsole console, infoput;
	private List<String> lst;
	private boolean enddead = false;
	private int nestlv;
	private int pause;
	private int quote;
	private int chr;
	private int counter;
	private int regX, regY;
	private Quadro.Direction todir;

	//
	NinaParser(Quadro q, NinaAction action,
			Map<String, String> prms,
			NinaSubautomata subs,
			NinaConsole cons,
			NinaConsole info) {
		this.q = q;
		this.action  = action;
		this.params  = new HashMap<String, String>(prms);
		this.subfas  = subs;
		this.console = cons;
		this.infoput = info;
	}

	/**
	 * 
	 * @param n
	 * @param action
	 * @param prms
	 * @param subs
	 * @return
	 */
	public NinaAction compileSubautomaton(String n, NinaAction action,
			Map<String, String> prms, NinaSubautomata subs,
			String qtype) {
		InputStream in = null;
		NinaAction r;
		Quadro q;
		String s;

		try {
			console.print("process", n);
			s = Nina.getFAName(subfas, n);
			if((q = this.q.getSubQuadro(n)) != null) {
				q = q.prototype(this.q);
			} else if((in = Nina.findLib(n, libs)) != null) {
				q = Quadro.read(s, new InputStreamReader(in), libs);
			} else if((in = NinaLibrary.loadLibrary(n)) != null) {
				q = Quadro.read(s, new InputStreamReader(in), libs);
			} else {
				throw new NinaException("subautomatonnotfound", n);
			}
			if(qtype != null)  q.type = qtype;
			r = compile(q, action, libs, prms, subs, console, infoput,
					pause);
			console.print("processed", n);
			return r;
		} catch(IOException e) {
			throw new NinaException(e, "ioerror");
		} finally {
			if(in != null) {
				try {
					in.close();
				} catch(IOException e) {
					throw new NinaException(e, "ioerror");
				}
			}
		}
	}

	//
	static NinaAction compile(Quadro q,
			NinaAction action,
			List<String> libs,
			Map<String, String> prms,
			NinaSubautomata subs,
			NinaConsole cons,
			NinaConsole info,
			int p) {
		NinaAction o, a;
		NinaParser c;
		String x;

		c = new NinaParser(q, action, prms, subs, cons, info);
		try {
			if(libs != null)  c.libs = libs;
			while((o = c.step()) == null) {
				if((p & _PRINT) != 0) {
					if((p & _PAUSE) != 0 && System.in.read() == '\r') {
						System.in.read();
					}
					c.printTrace(System.out);
				}
			}

			if(action == null && c.action instanceof DFABuilder) {
				for(Map.Entry<String, LRObject> t : q.getLRObjects().entrySet()) {
					LRObject l = t.getValue();
					int z;

					if((z = l.howManyShiftReduceConflicts()) > 0) {
						info.pwarn("lrshiftreduceconflict", z,
								t.getKey());
					}

					if((z = l.howManyReduceReduceConflicts()) > 0) {
						info.pwarn("lrreducereduceconflict", z,
								t.getKey());
					}

					for(String s : l.getSubautomata().keySet()) {
						a = c.compileSubautomaton(s, new DFABuilder(),
								c.params, c.subfas, null);
						c.subfas.put(s, a);
					}

					x = l.getDefinition().getLexerName();
					if(x != null && x.length() > 0) {
						a = c.compileSubautomaton(x, new NFABuilder(),
								c.params, c.subfas, null);
						c.subfas.put(x, a);
					}
				}

				if(q.lexer != null && !c.subfas.containsKey(q.lexer)) {
					a = c.compileSubautomaton(q.lexer,
							new NFABuilder(), c.params, c.subfas,
							q.ltype);
					c.subfas.put(q.lexer, a);
				}
				q.checkRequire();
			}
		} catch(IOException e) {
			throw new NinaException(e, "ioerror");
		}
		return o;
	}

	/**
	 * 
	 * @param q
	 * @param libs
	 * @param prms
	 * @param subs
	 * @return
	 */
	public static NinaAction complie(Quadro q,
			List<String> libs,
			Map<String, String> prms,
			NinaSubautomata subs,
			NinaConsole cons,
			NinaConsole info) {
		return NinaParser.compile(q,
				null,
				libs != null ? new ArrayList<String>(libs) : null,
				prms,
				subs,
				cons,
				info,
				0);
	}

	/**
	 * 
	 * @param q
	 * @param prms
	 * @param subs
	 * @return
	 */
	public static NinaAction complie(Quadro q,
			Map<String, String> prms,
			NinaSubautomata subs,
			NinaConsole cons,
			NinaConsole info) {
		return NinaParser.compile(q, null, null, prms, subs, cons,
				info, 0);
	}

	private String getstr(char c) {
		char[] a = new char[1];

		a[0] = c;
		return new String(a);
	}

	private void metBord(char c) {
		String s, t;
		int x;

		if(type.equals(Character.TYPE)) {
			x = Nina.prendCharcode(q.getCharset(), c);
			action.setEdge(q, Integer.valueOf(x));
		} else if((t = q.getAlias(s = getstr(c))) != null) {
			metBord(t, '\'');
		} else if(type.equals(String.class)) {
			action.setEdge(q, s);
		} else if(type.equals(Class.class)) {
			action.setEdge(q, Character.valueOf(c));
		} else {
			throw new ClassCastException();
		}
	}

	private void metBord(String s, int qc) {
		Integer c;
		String t;

		if(type.equals(Character.TYPE)) {
			if(s.length() == 0) {
				throw new NinaException("emptystring");
			} else if(s.length() == 1 && qc == '\'') {
				c = Nina.prendCharcode(q.getCharset(), s.charAt(0));
				action.setEdge(q, c);
			} else {
				if(qc == '"') {
					q.options.put("enableLookahead", "true");
				}
				action.setEdgeCharSequence(q, s, qc);
			}
		} else if((t = q.getAlias(s)) != null) {
			metBord(t, qc);
		} else if(type.equals(String.class)) {
			action.setEdge(q, s);
		} else if(type.equals(Class.class)) {
			action.setEdge(q, s);
		} else if(type.isInstance(Integer.class) ||
				type.equals(Integer.TYPE)) {
			action.setEdge(q, Integer.valueOf(s));
		} else if(type.isInstance(Long.class) ||
				type.equals(Long.TYPE)) {
			action.setEdge(q, Long.valueOf(s));
		} else if(type.isInstance(Float.class) ||
				type.equals(Float.TYPE)) {
			action.setEdge(q, Double.valueOf(s));
		} else if(type.isInstance(Double.class) ||
				type.equals(Double.TYPE)) {
			action.setEdge(q, Double.valueOf(s));
		} else if(type.isInstance(java.math.BigInteger.class)) {
			action.setEdge(q, new java.math.BigInteger(s));
		} else if(type.isInstance(java.math.BigDecimal.class)) {
			action.setEdge(q, new java.math.BigDecimal(s));
		} else {
			throw new ClassCastException();
		}
	}

	private void metBordRes(String s, Map<String, String> mp) {
		NFA<Object, NFAState, Void> n;
		DFA<Object, NFAState, Void> d;
		String t, v;
		NFAState x;
		Matcher m;

		if(s.startsWith("ex:")) {
			action.setUserEdge(q, s.substring(3));
		} else if(s.startsWith("dy:")) {
			action.setEdgeDynamic(q, s.substring(3));
		} else if(s.startsWith("g:")) {
			action.setEdgeGrammar(q, s.substring(2));
		} else if((m = DIGI.matcher(s)).matches()) {
			if(type.equals(Character.TYPE)) {
				if(m.group(2).equals("*")) {
					action.setEdgeDigits(q, -1, m.group(1) != null);
				} else {
					action.setEdgeDigits(q,
							Integer.parseInt(m.group(2)),
							m.group(1) != null);
				}
			} else {
				throw new NinaException(this, "invalidalphabettype");
			}
		} else if((m = DIGH.matcher(s)).matches()) {
			if(type.equals(Character.TYPE)) {
				if(m.group(1).equals("*")) {
					action.setEdgeHexadecimal(q, -1);
				} else {
					action.setEdgeHexadecimal(q,
							Integer.parseInt(m.group(1)));
				}
			} else {
				throw new NinaException(this, "invalidalphabettype");
			}
		} else if((m = DIGO.matcher(s)).matches()) {
			if(type.equals(Character.TYPE)) {
				if(m.group(1).equals("*")) {
					action.setEdgeOctal(q, -1);
				} else {
					action.setEdgeOctal(q,
							Integer.parseInt(m.group(1)));
				}
			} else {
				throw new NinaException(this, "invalidalphabettype");
			}
		} else if((m = INDT.matcher(s)).matches()) {
			if((t = m.group(2)) == null) {
				action.setEdgeIndent(q, m.group(1), 0);
			} else {
				t = t.replaceFirst("^\\+", "");
				action.setEdgeIndent(q, m.group(1),
						Integer.parseInt(t));
			}
		} else if(s.equals(FLOT)) {
			action.setEdgeFloat(q);
		} else if(s.equals(IJAV)) {
			action.setEdgeIdentifier(q, "Java");
		} else if(s.equals(ID_C)) {
			action.setEdgeIdentifier(q, "C");
		} else if(s.indexOf("$c") >= 0 || s.indexOf("__c__") >= 0) {
			action.setUserEdge(q, s);
		} else if((m = ANYS.matcher(s)).matches()) {
			action.setEdgeSequence(q, null,
					Integer.valueOf(m.group(1)));
		} else if((m = CHSS.matcher(s)).matches()) {
			action.setEdgeSequence(q, CharSets.parse(m.group(1)),
					Integer.valueOf(m.group(2)));
		} else if((m = REPS.matcher(s)).matches()) {
			if(!subfas.containsKey(v = m.group(1))) {
				subfas.put(v, null);
				compileSubautomaton(v, action, mp, subfas, null);
			}

			if((t = m.group(2)) == null) {
				action.setEdgeRepeatedResource(q, v, null);
			} else if(!type.equals(Character.TYPE)) {
				action.setEdgeRepeatedResource(q, v, t);
			} else if(t.length() < 2) {
				action.setEdgeRepeatedResource(q, v, t.toCharArray());
			} else if(t.charAt(0) == '"' &&
					t.charAt(t.length() - 1) == '"') {
				action.setEdgeRepeatedResource(q, v,
						t.substring(1, t.length() - 1).toCharArray());
			} else if(t.charAt(0) == '`' &&
					t.charAt(t.length() - 1) == '`') {
				try {
					t = t.substring(1, t.length() - 1);
					x = new NFAState() {};
					n = RegexpParser.parse(t, x);
					d = ConvertedRangeDFA.convertDFA(n);
					action.setEdgeRepeatedResource(q, v, d);
				} catch (RegexParseException e) {
					throw new NinaException("invalidregex");
				}
			} else {
				action.setEdgeRepeatedResource(q, v, t.toCharArray());
			}
		} else {
			t = Nina.getFAName(subfas, s);
			if(action instanceof DFABuilder &&
					!subfas.containsKey(t)) {
				subfas.put(t, null);
				compileSubautomaton(t, action, mp, subfas, null);
			}
			action.setEdgeResource(q, this, t, mp, subfas);
		}
	}

	private void metBordCharset(String s) {
		if(type.equals(Character.TYPE)) {
			action.setEdge(q, CharSets.parse(s, q.getCharset()));
//			action.setEdge(q, CharsetParser.parse(s, q.getCharset()));
		} else {
			throw new ClassCastException();
		}
	}

	private void metBordNFA(NFA<Object, NFAState, Void> s) {
		action.setEdge(q, s);
	}

	private void metBordLabel(String l) {
		NFA<Object, NFAState, Void> nz;
		Set<String> d;
		NFAState z;
		Matcher m;
		String s;

		if(q.defines.containsKey(l)) {
			metBordDefine(l);
			return;
		}

		d = new HashSet<String>();
		for(String x = l;;) {
			if(d.contains(x)) {
				throw new NinaException("labelcirculate");
			}
			d.add(x);
			s = q.labelalias.get(x);

			if((m = LB_Q.matcher(s)).matches()) {
				metBord(m.group(1), '\'');
				return;
			} else if((m = LB_D.matcher(s)).matches()) {
				metBord(m.group(1), '"');
				return;
			} else if((m = LB_S.matcher(s)).matches()) {
				metBordCharset(m.group(1));
				return;
			} else if((m = LB_R.matcher(s)).matches()) {
				try {
					z  = new NFAState() {};
					nz = RegexpParser.parse(m.group(1), z);
					metBordNFA(nz);
					return;
				} catch(RegexParseException e) {
					throw new NinaException(this, "invalidregex");
				}
			} else if((m = LB_L.matcher(s)).matches()) {
				x = m.group(1);
			} else {
				metBord(s, '\'');
				return;
			}
		}
	}

	private void metBordDefine(String l) {
		Set<String> d = new HashSet<String>();
		Matcher m;
		String s;
		int a;

		for(String x = l;;) {
			if(d.contains(x)) {
				throw new NinaException("labelcirculate");
			}
			d.add(x);
			s = q.defines.get(x);

			if((m = LD_H.matcher(s)).matches()) {
				metBord((char)(a = Integer.valueOf(m.group(1), 16)));
				q.consts.put(l, a);
				return;
			} else if((m = LD_O.matcher(s)).matches()) {
				metBord((char)(a = Integer.valueOf(s, 8)));
				q.consts.put(l, a);
				return;
			} else if((m = LD_D.matcher(s)).matches()) {
				metBord((char)(a = Integer.valueOf(s)));
				q.consts.put(l, a);
				return;
			} else {
				x = s;
			}
		}
	}

	private void metmealy() {
		action.setMealyEdgeType(chr);
		action.setMealyEdge(buf.reverse().toString());
		chr = -1;
	}

	String getParameter(String s) {
		return params.containsKey(s) ? params.get(s) : "";
	}

	private NinaAction getAutomatonClass(String s) {
		String t;

		t = Nina.getAutomatonName(s);
		pragmas.put("machine", t);
		q.options.put("machine", t);
		if(t.indexOf('.') < 0) {
			t = getClass().getPackage().getName() + "." + t;
		}
		return (NinaAction)Nina.prendClasse(t);
	}

	private void settype(String s) {
		if(q.type != null) {
			return;
		} else if(s.equals("char")) {
			type = Character.TYPE;
		} else if(s.equals("int")) {
			type = Integer.TYPE;
		} else if(s.equals("long")) {
			type = Long.TYPE;
		} else if(s.equals("float")) {
			type = Float.TYPE;
		} else if(s.equals("double")) {
			type = Double.TYPE;
		} else if(s.equals("string")) {
			type = String.class;
		} else if(s.equals("class")) {
			type = Class.class;
		} else {
			type = (Class<?>)Nina.prendClasse(s);
		}
		pragmas.put("type", q.type = s);
	}

	//
	NinaAction step() {
		NFA<Object, NFAState, Void> nz;
		Map<String, String> mp;
		NinaFrameReader rd;
		StringBuffer bt;
		NinaAction n;
		String s, t;
		NFAState dm;
		Object o;
		int c;
		S z;

		switch(z = etat) {
		case INIT:
			if(q.get() == '#') {
				buf = new StringBuffer();
				q.east();
				etat = S.PRAG0;
			} else if(q.get() == '%') {
				q.east();
				etat = S.DEF1;
			} else if(q.isBlankY()) {
				// an empty file
//				throw new NinaException(this, "unexpectedeof");
				infoput.pwarn("emptylanguage");
				n = new DFABuilder();
				t = q.getName();
				if(subfas.containsKey(t))  subfas.put(t, n);
				return n.empty(q, t);
			} else if(!q.isBlankX()) {
				etat = S.LINIT;
			}
			break;
		case PRAG0:
			if(q.get() == ' ') {
				q.east();
				etat = S.LICN1;
			} else if(q.isBlankX()) {
				q.license.append(NL);
				q.cr();
				etat = S.INIT;
			} else {
				etat = S.PRAG;
			}
			break;
		case LICN1:
			if(q.isBlankX()) {
				q.license.append(NL);
				q.cr();
				etat = S.INIT;
			} else if(q.isBlankY()) {
				throw new NinaException(this, "unexpectedeof");
			} else if(q.get() >= 0) {
				q.license.append((char)q.get());
				q.east();
			} else {
				q.east();
			}
			break;
		case PRAG:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else if(q.isLetter()) {
				buf.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else if(!Character.isWhitespace(q.get())) {
				q.set(' ');  q.east();
				etat = S.COMNT;
			} else if(buf.toString().equals("package")) {
				buf = new StringBuffer();
				q.east();
				etat = S.PACK;
			} else if(buf.toString().equals("machine")) {
				buf = new StringBuffer();
				q.east();
				etat = S.MACHN;
			} else if(buf.toString().equals("type")) {
				buf = new StringBuffer();
				q.east();
				etat = S.TYPE;
			} else if(buf.toString().equals("option")) {
				buf = new StringBuffer();
				q.east();
				etat = S.OPTN;
			} else if(buf.toString().equals("label")) {
				buf = new StringBuffer();
				q.east();
				etat = S.PLB_1;
			} else if(buf.toString().equals("define")) {
				buf = new StringBuffer();
				q.east();
				etat = S.PDF_1;
			} else if(buf.toString().equals("alias")) {
				buf = new StringBuffer();
				q.east();
				etat = S.ALIAS;
			} else if(buf.toString().equals("require")) {
				buf = new StringBuffer();
				q.east();
				etat = S.REQ1;
			} else if(buf.toString().equals("valtype")) {
				buf = new StringBuffer();
				q.east();
				etat = S.VTYP1;
			} else {
				etat = S.COMNT;
			}
			break;
		case PACK:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(' ');  q.east();
			} else if(q.isLetter() || q.isDigit() || q.get() == '.') {
				buf.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				q.setRootPackage(s = buf.toString().trim());
				q.setRootResource("/" + s.replace('.', '/'));
				pragmas.put("package", s);
				etat = S.COMNT;
			}
			break;
		case MACHN:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(' ');  q.east();
			} else if(q.isLetter() || q.get() == '.') {
				buf.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				s = buf.toString().trim();
				n = getAutomatonClass(s);
				t = Nina.getFAName(subfas, q.getName());

				if(subfas.containsKey(t))  subfas.put(t, n);
				if(action == null) {
					action = n;
				} else if(action.getClass().equals(DFABuilder.class) &&
						n.getClass().equals(DFABuilder.class)) {
					action = n;
				} else if(action.getClass().equals(NFABuilder.class) &&
						n.getClass().equals(DFABuilder.class)) {
					// do nothing
				} else if(action.getClass().equals(NFABuilder.class) &&
						n.getClass().equals(NFABuilder.class)) {
					// do nothing
				} else if(!action.getClass().equals(n.getClass())) {
					throw new NinaException(this, "unknownmachine", s);
				}
				etat = S.COMNT;
			}
			break;
		case TYPE:
			if(q.type != null) {
				etat = S.COMNT;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(' ');  q.east();
			} else if(q.get() == '>') {
				q.set(' ');  q.east();
				bf2 = new StringBuffer();
				etat = S.TYP2;
			} else if(q.isLetter() || q.get() == '.') {
				buf.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				settype(buf.toString().trim());
				etat = S.COMNT;
			}
			break;
		case TYP2:
			if(q.get() == '>') {
				q.lexer = bf2.toString().trim();
				bf2 = new StringBuffer();
				q.set(' ');  q.east();
				etat = S.TYP3;
			} else if(q.isLetter() || q.get() == '.') {
				bf2.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				settype(buf.toString().trim());
				etat = S.COMNT;
			}
			break;
		case TYP3:
			if(q.isLetter() || q.get() == '.') {
				bf2.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				q.ltype = buf.toString().trim();
				settype(bf2.toString().trim());
				etat = S.COMNT;
			}
			break;
		case OPTN:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(' ');  q.east();
			} else if(q.get() == '=') {
				bf2 = new StringBuffer();
				q.set(' ');  q.east();
				etat = S.OPTV;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				q.options.put(buf.toString(), "");
				etat = S.COMNT;
			}
			break;
		case OPTV:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(' ');  q.east();
			} else if(q.get() == '\'') {
				q.set(' ');  q.east();
				etat = S.OPTQ;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				s = buf.toString();
				q.options.put(s, bf2.toString());
				etat = S.COMNT;
			}
			break;
		case OPTQ:
			if(q.get() == '\'') {
				q.set(' ');  q.east();
				etat = S.OPTV;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				throw new NinaException(this, "invalidoption");
			}
			break;
		case ALIAS:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(' ');  q.east();
			} else if(q.get() == '=') {
				bf2 = new StringBuffer();
				q.set(' ');  q.east();
				etat = S.ALI_V;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				q.options.put(buf.toString(), "");
				etat = S.COMNT;
			}
			break;
		case ALI_V:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(' ');  q.east();
			} else if(q.get() == '\'') {
				q.set(' ');  q.east();
				etat = S.ALI_Q;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				q.options.put(buf.toString(), bf2.toString());
				etat = S.COMNT;
			}
			break;
		case ALI_Q:
			if(q.get() == '\'') {
				q.set(' ');  q.east();
				etat = S.ALI_V;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				throw new NinaException(this, "invalidalias");
			}
			break;
		case PLB_1:
			if(q.get() == Quadro.EQ_TO_LEFT || q.get() == '\r') {
				q.set(' ');  q.east();
			} else if(q.get() == '=') {
				bf2 = new StringBuffer();
				q.set(' ');  q.east();
				etat = S.PLB_2;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				throw new NinaException(this, "invalidlabeldef");
			}
			break;
		case PLB_2:
			if(q.get() == Quadro.EQ_TO_LEFT || q.get() == '\r') {
				q.set(' ');  q.east();
			} else if(q.isBlankX()) {
				q.labelalias.put(buf.toString(), bf2.toString());
				q.cr();
				etat = S.INIT;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				throw new NinaException(this, "invalidlabeldef");
			}
			break;
		case PDF_1:
			if(q.get() == Quadro.EQ_TO_LEFT || q.get() == '\r') {
				q.set(' ');  q.east();
			} else if(q.get() == ' ') {
				bf2 = new StringBuffer();
				q.east();
				etat = S.PDF_2;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				throw new NinaException(this, "invalidlabeldef");
			}
			break;
		case PDF_2:
			if(q.get() == Quadro.EQ_TO_LEFT || q.get() == '\r') {
				q.set(' ');  q.east();
			} else if(q.get() == ' ') {
				q.east();
			} else if(q.get() >= 0) {
				etat = S.PDF_3;
			} else {
				throw new NinaException(this, "invalidlabeldef");
			}
			break;
		case PDF_3:
			if(q.get() == Quadro.EQ_TO_LEFT || q.get() == '\r') {
				q.set(' ');  q.east();
			} else if(q.isBlankX()) {
				q.defines.put(buf.toString(), bf2.toString());
				q.cr();
				etat = S.INIT;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				throw new NinaException(this, "invalidlabeldef");
			}
			break;
		case REQ1:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(' ');  q.east();
			} else if(q.get() == ' ') {
				bf2 = new StringBuffer();
				q.east();
				etat = S.REQ2;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				q.requires.add(new String[] { buf.toString(), null });
				etat = S.COMNT;
			}
			break;
		case REQ2:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(' ');  q.east();
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				q.requires.add(
						new String[] { buf.toString(), bf2.toString() });
				etat = S.COMNT;
			}
			break;
		case VTYP1:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(' ');  q.east();
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.set(' ');  q.east();
			} else {
				q.valtype = buf.toString();
				q.options.put("valtype", q.valtype);
				etat = S.COMNT;
			}
			break;
		case COMNT:
			if(q.isBlankX()) {
				q.cr();
				etat = S.INIT;
			} else if(q.isBlankY()) {
				throw new NinaException(this, "unexpectedeof");
			} else {
				q.set(' ');  q.east();
			}
			break;
		case DEF1:
			if(q.get() == '{') {
				buf  = new StringBuffer();
				defs = new StringWriter();
				def  = new PrintWriter(defs);
				q.east();
				etat = S.DEF2;
			} else if(q.get() >= 'a' && q.get() <= 'z') {
				buf = new StringBuffer();
				etat = S.DEFI1;
			} else {
				q.west();
				etat = S.LINIT;
			}
			break;
		case DEF2:
			if(q.isBlankY()) {
				throw new NinaException(this, "unexpectedeof");
			} else if(q.isBlankX()) {
				def.println();
				q.cr();
			} else if(q.get() == '%') {
				q.east();
				etat = S.DEF3;
			} else if(q.get() >= 0) {
				def.print((char)q.get());
				q.east();
			}
			break;
		case DEF3:
			if(q.get() == '}') {
				StringBuffer b;
				String x;

				def.println();
				x = buf.toString();
				if((b = q.buffers.get(x)) == null) {
					q.buffers.put(x, b = new StringBuffer());
				}
				b.append(defs.toString());
				buf = new StringBuffer();
				q.east();
				etat = S.DEF4;
			} else {
				def.print('%');
				etat = S.DEF2;
			}
			break;
		case DEF4:
			if(q.isBlankX()) {
				q.cr();
				etat = S.INIT;
			} else {
				q.east();
			}
			break;
		case DEFI1:
			if(q.get() == '{') {
				defs = new StringWriter();
				def  = new PrintWriter(defs);
				q.east();
				etat = S.DEF2;
			} else if(Character.isWhitespace(q.get())) {
				q.east();
				etat = S.DEFI2;
			} else if(q.get() >= 'a' && q.get() <= 'z') {
				buf.append((char)q.get());
				q.east();
			} else {
				buf = new StringBuffer();
				q.cr();
				etat = S.INIT;
			}
			break;
		case DEFI2:
			if(q.get() == '{') {
				defs = new StringWriter();
				def  = new PrintWriter(defs);
				q.east();
				etat = S.DEF2;
			} else if(Character.isWhitespace(q.get())) {
				q.east();
			} else {
				buf = new StringBuffer();
				q.cr();
				etat = S.INIT;
			}
			break;
		case LINIT:
			if(action == null) {
				t = q.getName();
				action = new DFABuilder();
				if(subfas.containsKey(t))  subfas.put(t, action);
			}

			if(_FRAME1.equals(q.getScratch2())) {
				q.east();
			} else if(_FRAME2.equals(q.getScratch2())) {
				q.east();
				etat = S.LINI2;
			} else if(q.isFrameBefore()) {
				if(q.get() == '=' || q.get() == '&') {
					etat = S.FI_E;
				} else {
					buf = new StringBuffer();
					bf2 = new StringBuffer();
					q.east();
					etat = S.FI_L0;
				}
			} else if(q.get() == '\'' || q.get() == '"') {
				quote = q.get();
				q.east();
				etat = S.LQUOT;
			} else if(q.get() == '[') {
				q.east();
				etat = S.LCSET;
			} else if(q.get() == '`') {
				q.east();
				etat = S.LGNFA;
			} else if(q.get() == '{') {
				q.east();
				etat = S.LSNFA;
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.isBlankY()) {
				q.north();
				etat = S.LPRI1;
			} else {
				q.east();
			}
			break;
		case LINI2:
			if(_FRAME2.equals(q.getScratch2()))  etat = S.LINIT;
			q.east();
			break;
		case FI_L0:
			if(q.get() == '\'') {
				etat = S.FI_L1;
			} else if(q.get() == '_' ||
					Character.isUpperCase(q.get())) {
				etat = S.FI_L1;
			} else if(q.get() == '<') {
				etat = S.FI_L1;
			} else if(q.isFrameBefore() || q.isArrow()) {
				etat = S.FI_L1;
			} else {
				etat = S.LINIT;
			}
			break;
		case FI_L1:
			if(q.get() == '\'') {
				q.set('*');
				q.east();
				etat = S.FI_L3;
			} else if(q.get() == '_' ||
					Character.isUpperCase(q.get())) {
				buf.appendCodePoint(q.get());
				q.set('*');
				q.east();
			} else if(q.get() == '<') {
				q.set('*');
				q.east();
				nestlv = 1;
				etat = S.FI_L4;
			} else if(q.isFrameBefore() || q.isArrow()) {
				q.west();
				etat = S.FI_L2;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FI_L2:
			if(q.isFrameBefore()) {
				q.west();
			} else if(q.get() >= 0) {
				q.east();
				q.setLabel(buf.toString());
				q.setLabelType(bf2.toString());
				buf = new StringBuffer();
				bf2 = new StringBuffer();
				etat = S.FI_E;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FI_L3:
			if(q.get() == '\'') {
				q.set('*');
				q.east();
				etat = S.FI_L1;
			} else if(q.get() == '<') {
				bf2 = new StringBuffer();
				q.set('*');
				q.east();
				nestlv = 1;
				etat = S.FI_L4;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.set('*');
				q.east();
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FI_L4:
			if(q.get() == '>' && --nestlv <= 0) {
				q.set('*');
				q.west();
				etat = S.FI_L2;
			} else if(q.get() >= 0) {
				if(q.get() == '<') {
					nestlv++;
				}
				bf2.appendCodePoint(q.get());
				q.set('*');
				q.east();
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FI_E:
			q.south();
			if(q.isFrameBefore() || q.isArrow()) {
				q.north();
				if(q.get() == '=' || q.get() == '&') {
					q.setLabel(STARTSYM);
				}
				etat = S.FI_E2;
			} else {
				q.north().east();
				etat = S.LINIT;
			}
			break;
		case FI_E2:
			if(q.isFrameBefore() || q.isArrow() || q.isEntry() ||
					q.isDone()) {
				q.transformFrame();
				q.setScratch2(_FRAME1);
				q.east();
			} else {
				q.south().west();
				etat = S.FI_S;
			}
			break;
		case FI_S:
			if(q.isFrameBefore() || q.isFrame() ||
					q.isArrow() || q.isEntry() || q.isDone()) {
				etat = S.FI_S2;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FI_S2:
			if(q.isFrameBefore() || q.isFrame() ||
					q.isArrow() || q.isEntry() || q.isDone()) {
				q.transformFrame();
				q.setScratch2(_FRAME2);
				q.south();
			} else {
				q.north();
				etat = S.FI_W;
			}
			break;
		case FI_W:
			q.west();
			if(q.isFrameBefore() || q.isFrame() ||
					q.isArrow() || q.isEntry() || q.isDone()) {
				q.east();
				etat = S.FI_W2;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FI_W2:
			if(q.isFrameBefore() || q.isFrame() ||
					q.isArrow() || q.isEntry() || q.isDone()) {
				q.transformFrame();
				q.setScratch2(_FRAME1);
				q.west();
			} else {
				q.north().east();
				etat = S.FI_N;
			}
			break;
		case FI_N:
			if(q.isFrameBefore() ||
					q.isArrow() || q.isEntry() || q.isDone()) {
				q.transformFrame();
				q.setScratch2(_FRAME2);
				q.north();
			} else if(q.isFrame()) {
				q.setScratch2(_FRAME1);
				etat = S.LINIT;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case LQUOT:
			if(q.get() == quote) {
				q.east();
				etat = S.LINIT;
			} else if(q.get() == '\\') {
				q.east();
				q.east();
			} else if(q.get() >= 0 || q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else {
				throw new NinaException(this, "invalidquote");
			}
			break;
		case LSNFA:
			if(q.get() == '}') {
				q.east();
				etat = S.LINIT;
			} else if(q.get() >= 0 || q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else {
				throw new NinaException(this, "invalidsubfa");
			}
			break;
		case LCSET:
			if(q.get() == ']') {
				q.east();
				etat = S.LINIT;
			} else if(q.get() >= 0 || q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else {
				throw new NinaException(this, "invalidchrst");
			}
			break;
		case LGNFA:
			if(q.get() == '`') {
				q.east();
				etat = S.LINIT;
			} else if(q.get() >= 0 || q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else {
				throw new NinaException(this, "invalidregex");
			}
			break;
		case LPRI1:
			if(q.isBlankY()) {
				q.south();
				etat = S.LPRI2;
			} else {
				q.north();
			}
			break;
		case LPRI2:
			if(q.isBlankY()) {
				// an empty language
//				throw new NinaException(this, "unexpectedeof");
				infoput.pwarn("emptylanguage");
				return action.empty(q, q.getName());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(STARTSYM.equals(q.getLabel())) {
				action.setStartState(action.createState(q));
				etat = S.LBLE;
			} else {
				q.east();
			}
			break;
		case LBLE:
			if(q.isFrame() || q.isArrow() || q.isEntry() ||
					q.isDone()) {
				q.setScratch2(_FRAME1);
				q.east();
			} else {
				q.south().west();
				etat = S.FL_S;
			}
			break;
		case FL_S:
			if(q.isFrame() || q.isArrow() || q.isEntry() ||
					q.isDone()) {
				q.setScratch2(_FRAME2);
				q.south();
			} else {
				q.north().west();
				etat = S.FL_W;
			}
			break;
		case FL_W:
			if(q.isFrame() || q.isArrow() || q.isEntry() ||
					q.isDone()) {
				q.setScratch2(_FRAME1);
				q.west();
			} else {
				q.north().east();
				etat = S.FL_N;
			}
			break;
		case FL_N:
			if(q.isFrame() || q.isArrow() || q.isEntry() ||
					q.isDone()) {
				q.setScratch2(_FRAME2);
				q.north();
			} else {
				q.south();
				q.setScratch2(_FRAME1);
				etat = S.FL_E;
			}
			break;
		case FL_E:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				c = q.get();
				q.south().east();
				rd = new NinaFrameReader(q);
				action.labelAdded(q, rd, c == Quadro.FRAME_A);
				rd.close();
			}
			etat = S.PRI01;
			break;
		case PRI01:
			buf = new StringBuffer();
			q.north();
			etat = S.PRI02;
			break;
		case PRI02:
			if(q.get() >= '0' && q.get() <= '9') {
				etat = S.PRI03;
			} else {
				q.south();
				etat = S.FMNW;
			}
			break;
		case PRI03:
			if(q.get() >= '0' && q.get() <= '9') {
				buf.append((char)q.get());
				q.east();
			} else {
				if(buf.length() > 0) {
					action.setPriority(Integer.valueOf(
							buf.toString()));
				}
				etat = S.PRI04;
			}
			break;
		case PRI04:
			if(q.get() >= '0' && q.get() <= '9') {
				q.west();
			} else {
				q.east().south();
				etat = S.FMNW;
			}
			break;
		case FMNW:
			q.setScratch(action.getVertex());
			if(q.isFrame()) {
				q.east();
				etat = S.FMNW2;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FMNW2:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				etat = S.FM_E;
			} else {
				throw new NinaException(this, "invalidframe");
			}
		case FM_E:
			q.setScratch(action.getVertex());
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.east();
			} else if(q.isDone()) {
				q.west();
				etat = S.FRR_W;
			} else {
				q.west();
				etat = S.FMNE;
			}
			break;
		case FMNE:
			if(q.isFrame()) {
				q.south();
				etat = S.FMNE2;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FMNE2:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				etat = S.FM_S;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FM_S:
			q.setScratch(action.getVertex());
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.south();
			} else if(q.isDone()) {
				q.north();
				etat = S.FRR_N;
			} else {
				q.north();
				etat = S.FMSE;
			}
			break;
		case FMSE:
			if(q.isFrame()) {
				q.west();
				etat = S.FMSE2;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FMSE2:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				etat = S.FM_W;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FM_W:
			q.setScratch(action.getVertex());
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.west();
			} else if(q.isDone()) {
				q.east();
				etat = S.FRR_E;
			} else {
				q.east();
				etat = S.FMSW;
			}
			break;
		case FMSW:
			if(q.isFrame()) {
				etat = S.FMSW2;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FMSW2:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				etat = S.FM_N;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FM_N:
			q.setScratch(action.getVertex());
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.north();
			} else if(q.isDone()) {
				q.south();
				etat = S.FRNW;
			} else {
				q.south();
				etat = S.FRNW;
				action.doneBlockSearching(q);
			}
			break;
		case FRNW:
			if(q.isFrame()) {
				q.east();
				etat = S.FRNW2;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FRNW2:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				etat = S.FR_E;
			} else {
				throw new NinaException(this, "invalidframe");
			}
		case FR_E:
			if(q.get() == '^') {
				action.setVertex(q.getScratch());
				action.setEdge(q, null);
				q.north();
				etat = S.AR_N;
			} else if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.east();
			} else if(q.isDone()) {
				q.west();
				etat = S.FRR_W;
			} else {
				q.west();
				etat = S.FRNE;
			}
			break;
		case FRNE:
			if(q.isFrame()) {
				q.south();
				etat = S.FRNE2;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FRNE2:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				etat = S.FR_S;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FR_S:
			if(q.get() == '>') {
				action.setVertex(q.getScratch());
				action.setEdge(q, null);
				q.east();
				etat = S.AR_E;
			} else if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.south();
			} else if(q.isDone()) {
				q.north();
				etat = S.FRR_N;
			} else {
				q.north();
				etat = S.FRSE;
			}
			break;
		case FRSE:
			if(q.isFrame()) {
				q.west();
				etat = S.FRSE2;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FRSE2:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				etat = S.FR_W;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FR_W:
			if(q.get() == 'v') {
				action.setVertex(q.getScratch());
				action.setEdge(q, null);
				q.south();
				etat = S.AR_S;
			} else if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.west();
			} else if(q.isDone()) {
				q.east();
				etat = S.FRR_E;
			} else {
				q.east();
				etat = S.FRSW;
			}
			break;
		case FRSW:
			if(q.isFrame()) {
				etat = S.FRSW2;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FRSW2:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				etat = S.FR_N;
			} else {
				throw new NinaException(this, "invalidframe");
			}
			break;
		case FR_N:
			if(q.get() == '<') {
				action.setVertex(q.getScratch());
				action.setEdge(q, null);
				q.west();
				etat = S.AR_W;
			} else if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.north();
			} else if(q.isDone()) {
				q.south();
				etat = S.FRR_S;
			} else {
				q.south();
				etat = S.FRR_S;
				action.doneBlockSearching(q);
			}
			break;
		case AR_N:
			if(q.get() == '/') {
				q.set(Quadro.S2);
				q.east();
				etat = S.AR_E;
			} else if(q.get() == '\\') {
				q.set(Quadro.S2);
				q.west();
				etat = S.AR_W;
			} else if(q.get() == '|') {
				q.set(Quadro.S2);
				q.north();
			} else if(q.isBranchN()) {
				q.setScratch(new Z(action.getVertex(), q.getEdge()));
				q.set(Quadro.putWedgeN(q.get()));
				q.north();
				etat = S.BR_N;
			} else if(q.get() == '.') {
				q.setEdge(CharSets.ALL_CHAR);
				q.set(Quadro.S2);
				q.north();
			} else if(q.get() == '^') {
				action.link(q, o = q.getScratch());
				if(o != null) {
					q.south();
					etat = S.ARR_S;
				} else {
					q.set(Quadro.ENTRY);
					etat = S.F2_W;
				}
			} else if(q.get() == '$') {
				action.setEdgeEnd(q);
				q.set(Quadro.S2);
				q.north();
			} else if(q.get() == '*' || q.get() == '@') {
				if(q.getScratch() != null) {
					throw new NinaException("notjoin");
				} else {
					action.link(q, null);
					action.setAccept(q.get() == '@');
					q.setScratch(Integer.valueOf(q.get()));
					etat = S.ONS_0;
				}
			} else if(q.isLetter() || q.isDigit()) {
				q.setEdge(Integer.valueOf((char)q.get()));
				q.set(Quadro.S2);
				q.north();
			} else if(q.isArrow2() || q.isArrow3()) {
				q.south();
				etat = S.AR_ZE;
			} else if(q.get() == Quadro.DONE) {
				action.link(q, q.getScratch());
				q.south();
				etat = S.ARR_S;
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case AR_ZE:
			q.set('^');
			q.east();
			etat = S.FR_E;
			break;
		case AR_E:
			if(q.get() == '/') {
				q.set(Quadro.W2);
				q.north();
				etat = S.AR_N;
			} else if(q.get() == '\\') {
				q.set(Quadro.W2);
				q.south();
				etat = S.AR_S;
			} else if(q.get() == '-') {
				q.set(Quadro.W2);
				q.east();
			} else if(q.isBranchE()) {
				q.setScratch(new Z(action.getVertex(), q.getEdge()));
				q.set(Quadro.putWedgeN(q.get()));
				q.north();
				etat = S.BR_N;
			} else if(q.get() == '.') {
				q.setEdge(CharSets.ALL_CHAR);
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_ES;
			} else if(q.get() == '>') {
				action.link(q, o = q.getScratch());
				if(o != null) {
					q.west();
					etat = S.ARR_W;
				} else {
					q.set(Quadro.ENTRY);
					etat = S.F2_N;
				}
			} else if(q.get() == '\'' || q.get() == '"') {
				quote = q.get();
				q.set(Quadro.W2);
				q.east();
				buf = new StringBuffer();
				etat = S.AR_EQ;
			} else if(q.get() == '{') {
				q.set(Quadro.W2);
				q.east();
				buf = new StringBuffer();
				etat = S.AR_ER;
			} else if(q.get() == '[') {
				nestlv = 0;
				q.set(Quadro.W2);
				q.east();
				buf = new StringBuffer();
				etat = S.AR_EI;
			} else if(q.get() == '(') {
				q.set(Quadro.WARP2);
				q.east();
				buf = new StringBuffer();
				etat = S.WP_E1;
			} else if(q.get() == '$') {
				q.set(Quadro.W2);
				q.east();
				buf = new StringBuffer();
				etat = S.AREE1;
			} else if(q.get() == '0') {
				buf = new StringBuffer();
				q.set(Quadro.W2);
				q.east();
				etat = S.AREN0;
			} else if(q.get() >= '1' && q.get() <= '9') {
				buf = new StringBuffer();
				chr = 10;
				etat = S.AREN1;
			} else if(q.get() == '*' || q.get() == '@') {
				if(q.getScratch() != null) {
					throw new NinaException("notjoin");
				} else {
					action.link(q, null);
					action.setAccept(q.get() == '@');
					q.setScratch(Integer.valueOf(q.get()));
					etat = S.ONS_0;
				}
			} else if(q.isLetter() || q.isDigit()) {
				metBord((char)q.get());
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_ES;
			} else if(q.isArrow2() || q.isArrow3()) {
				q.west();
				etat = S.AR_ZS;
			} else if(q.get() == '`') {
				q.set(Quadro.W2);
				q.east();
				buf = new StringBuffer();
				etat = S.AR_EG;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.W2);
				q.east();
			} else if(q.get() == Quadro.DONE) {
				action.link(q, q.getScratch());
				q.west();
				etat = S.ARR_W;
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case AR_ZS:
			q.set('>');
			q.south();
			etat = S.FR_S;
			break;
		case AREN0:
			if(q.get() == 'x' || q.get() == 'X') {
				chr = 16;
				q.set(Quadro.W2);
				q.east();
			} else {
				chr = 8;
			}
			etat = S.AREN1;
			break;
		case AREN1:
			if((q.get() >= '0' && q.get() <= '7') ||
					(chr > 8  && q.get() >= '8' && q.get() <= '9') ||
					(chr > 10 && q.get() >= 'a' && q.get() <= 'f') ||
					(chr > 10 && q.get() >= 'A' && q.get() <= 'F')) {
				buf.append((char)q.get());
				q.set(Quadro.W2);
				q.east();
			} else {
				metBord((char)Integer.parseInt(buf.toString(), chr));
				buf  = new StringBuffer();
				chr  = -1;
				etat = S.AR_ES;
			}
			break;
		case AR_EQ:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidquote");
			} else if(q.get() == quote) {
				metBord(buf.toString(), quote);
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_ES;
			} else if(q.get() == '\\') {
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_Eq;
			} else if(q.get() == '$') {
				bf2 = new StringBuffer();
				q.set(Quadro.W2);
				q.east();
				etat = S.ARED1;
			} else if(q.get() >= 0) {
				buf.append((char)q.get());
				q.set(Quadro.W2);
				q.east();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.W2);
				q.east();
			} else {
				throw new NinaException(this, "invalidquote");
			}
			break;
		case AR_Eq:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidquote");
			} else if(q.get() >= 0) {
				if(q.get() == 'n') {
					buf.append('\n');
				} else if(q.get() == 'r') {
					buf.append('\r');
				} else if(q.get() == 't') {
					buf.append('\t');
				} else if(q.get() == '0') {
					buf.append('\0');
				} else if(q.get() != '\'' && q.get() != '\\') {
					buf.append('\\');
					buf.append((char)q.get());
				} else {
					buf.append((char)q.get());
				}
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_EQ;
			} else {
				throw new NinaException(this, "invalidquote");
			}
			break;
		case ARED1:
			if(q.get() == '{') {
				q.set(Quadro.W2);
				q.east();
				etat = S.ARED2;
			} else {
				buf.append('$');
				etat = S.AR_EQ;
			}
			break;
		case ARED2:
			if(q.get() == '}') {
				buf.append(getParameter(bf2.toString()));
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_EQ;
			} else if(Character.isJavaIdentifierPart(q.get())) {
				bf2.appendCodePoint(q.get());
				q.set(Quadro.W2);
				q.east();
			} else {
				buf.append('$');  buf.append('{');
				buf.append(bf2);
				etat = S.AR_EQ;
			}
			break;
		case AR_ER:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidsubfa");
			} else if(q.get() == '(') {
				bf2 = new StringBuffer();
				lst = new ArrayList<String>();
				q.set(Quadro.W2);
				q.east();
				etat = S.ARER1;
			} else if(q.get() == '}') {
				metBordRes(buf.toString(),
						Collections.<String, String>emptyMap());
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_ES;
			} else if(q.get() >= 0) {
				buf.append((char)q.get());
				q.set(Quadro.W2);
				q.east();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.W2);
				q.east();
			} else {
				throw new NinaException(this, "invalidsubfa");
			}
			break;
		case ARER1:
			if(q.get() == ')') {
				q.set(Quadro.W2);
				q.east();
				etat = S.ARER2;
			} else if(q.get() == ',') {
				lst.add(bf2.toString());
				bf2 = new StringBuffer();
				q.set(Quadro.W2);
				q.east();
			} else if(q.get() == '\'') {
				q.set(Quadro.W2);
				q.east();
				etat = S.ARER3;
			} else if(q.get() == '"') {
				q.set(Quadro.W2);
				q.east();
				etat = S.ARER4;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(Quadro.W2);
				q.east();
			} else {
				throw new NinaException(this, "invalidsubfa");
			}
			break;
		case ARER2:
			if(q.get() == '}') {
				lst.add(bf2.toString());  bf2 = null;
				mp = new HashMap<String, String>();
				for(int k = 1; k <= lst.size(); k++) {
					mp.put(k + "", lst.get(k - 1));
				}
				metBordRes(buf.toString(), mp);
				lst = null;
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_ES;
			} else {
				throw new NinaException(this, "invalidsubfa");
			}
			break;
		case ARER3:
			if(q.get() == '\'') {
				q.set(Quadro.W2);
				q.east();
				etat = S.ARER1;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(Quadro.W2);
				q.east();
			} else {
				throw new NinaException(this, "invalidsubfa");
			}
			break;
		case ARER4:
			if(q.get() == '"') {
				q.set(Quadro.W2);
				q.east();
				etat = S.ARER1;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(Quadro.W2);
				q.east();
			} else {
				throw new NinaException(this, "invalidsubfa");
			}
			break;
		case AR_EI:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidchrst");
			} else if(q.get() == '\\') {
				q.set(Quadro.W2);  q.east();
				etat = S.AR_Ei;
			} else if(q.get() == ']' && nestlv-- <= 0) {
				metBordCharset(buf.toString());
				q.set(Quadro.W2);  q.east();
				etat = S.AR_ES;
			} else if(q.get() >= 0) {
				if(q.get() == '[')  nestlv++;
				buf.append((char)q.get());
				q.set(Quadro.W2);
				q.east();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.W2);
				q.east();
			} else {
				throw new NinaException(this, "invalidchrst");
			}
			break;
		case AR_Ei:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidchrst");
			} else if(q.get() >= 0) {
				buf.append('\\');
				buf.append((char)q.get());
				q.set(Quadro.W2);  q.east();
				etat = S.AR_EI;
			} else {
				throw new NinaException(this, "invalidchrst");
			}
			break;
		case AR_EG:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidregex");
			} else if(q.get() == '\\') {
				q.set(Quadro.W2);  q.east();
				etat = S.AR_Eg;
			} else if(q.get() == '`') {
				try {
					dm = new NFAState() {};
					nz = RegexpParser.parse(buf.toString(), dm);
					metBordNFA(nz);
				} catch(RegexParseException e) {
					throw new NinaException(this, "invalidregex");
				}
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_E;
			} else if(q.get() >= 0) {
				buf.append((char)q.get());
				q.set(Quadro.W2);
				q.east();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.W2);
				q.east();
			} else {
				throw new NinaException(this, "invalidregex");
			}
			break;
		case AR_Eg:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidchrst");
			} else if(q.get() >= 0) {
				buf.append('\\');
				buf.append((char)q.get());
				q.set(Quadro.W2);  q.east();
				etat = S.AR_EG;
			} else {
				throw new NinaException(this, "invalidchrst");
			}
			break;
		case AR_ES:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidmealy");
			} else if(q.get() == '/' || q.get() == '#' ||
					q.get() == '%') {
				chr = q.get();
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_EM;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.W2);
				q.east();
			} else {
				etat = S.AR_E;
			}
			break;
		case AR_EM:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidmealy");
			} else if(q.isWhitespace()) {
				q.set(Quadro.W2);
				q.north().west();
				etat = S.AR_N;
			} else if(q.get() == '\'') {
				q.set(Quadro.W2);
				q.east();
				buf = new StringBuffer();
				etat = S.AR_EX;
			} else {
				throw new NinaException(this, "invalidmealy");
			}
			break;
		case AR_EX:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidmealy");
			} else if(q.get() == '\'') {
				action.setMealyEdgeType(chr);
				action.setMealyEdge(buf.toString());
				chr = -1;
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_E;
			} else if(q.get() >= 0) {
				buf.append((char)q.get());
				q.set(Quadro.W2);
				q.east();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.W2);
				q.east();
			} else {
				throw new NinaException(this, "invalidmealy");
			}
			break;
		case WP_E1:
			if(q.get() == ')') {
				q.set(Quadro.WARP2);
				etat = S.TOIX1;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.east();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case AREE1:
			if(q.get() == '{') {
				q.set(Quadro.W2);
				q.east();
				etat = S.AREE2;
			} else {
				action.setEdgeEnd(q);
				etat = S.AR_ES;
			}
			break;
		case AREE2:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.W2);
				q.east();
			} else if(q.get() == '}') {
				metBordLabel(buf.toString());
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_ES;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.set(Quadro.W2);
				q.east();
			} else {
				throw new NinaException(this, "invalidlabel");
			}
			break;
		case AR_S:
			if(q.get() == '/') {
				q.set(Quadro.N2);
				q.west();
				etat = S.AR_W;
			} else if(q.get() == '\\') {
				q.set(Quadro.N2);
				q.east();
				etat = S.AR_E;
			} else if(q.get() == '|') {
				q.set(Quadro.N2);
				q.south();
			} else if(q.isBranchS()) {
				q.setScratch(new Z(action.getVertex(), q.getEdge()));
				q.set(Quadro.putWedgeN(q.get()));
				q.north();
				etat = S.BR_N;
			} else if(q.get() == '.') {
				q.setEdge(CharSets.ALL_CHAR);
				q.set(Quadro.N2);
				q.south();
			} else if(q.get() == 'v') {
				action.link(q, o = q.getScratch());
				if(o != null) {
					q.north();
					etat = S.ARR_N;
				} else {
					q.set(Quadro.ENTRY);
					etat = S.F3_W;
				}
			} else if(q.get() == '$') {
				action.setEdgeEnd(q);
				q.set(Quadro.N2);
				q.south();
			} else if(q.get() == '*' || q.get() == '@') {
				if(q.getScratch() != null) {
					throw new NinaException("notjoin");
				} else {
					action.link(q, null);
					action.setAccept(q.get() == '@');
					q.setScratch(Integer.valueOf(q.get()));
					etat = S.ONS_0;
				}
			} else if(q.isLetter() || q.isDigit()) {
				metBord((char)q.get());
				q.set(Quadro.N2);
				q.south();
			} else if(q.isArrow2() || q.isArrow3()) {
				q.north();
				etat = S.AR_ZW;
			} else if(q.get() == Quadro.DONE) {
				action.link(q, q.getScratch());
				q.north();
				etat = S.ARR_N;
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case AR_ZW:
			q.set('v');
			q.west();
			etat = S.FR_W;
			break;
		case AR_W:
			if(q.get() == '/') {
				q.set(Quadro.E2);
				q.south();
				etat = S.AR_S;
			} else if(q.get() == '\\') {
				q.set(Quadro.E2);
				q.north();
				etat = S.AR_N;
			} else if(q.get() == '-') {
				q.set(Quadro.E2);
				q.west();
			} else if(q.isBranchW()) {
				q.setScratch(new Z(action.getVertex(), q.getEdge()));
				q.set(Quadro.putWedgeN(q.get()));
				q.north();
				etat = S.BR_N;
			} else if(q.get() == '.') {
				action.setEdge(q, CharSets.ALL_CHAR);
				q.set(Quadro.E2);
				q.west();
			} else if(q.get() == '<') {
				action.link(q, o = q.getScratch());
				if(o != null) {
					q.east();
					etat = S.ARR_E;
				} else {
					q.set(Quadro.ENTRY);
					etat = S.F3_N;
				}
			} else if(q.get() == '\'' || q.get() == '"') {
				quote = q.get();
				buf = new StringBuffer();
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WQ;
				buf = new StringBuffer();
			} else if(q.get() == '}') {
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WR;
				buf = new StringBuffer();
			} else if(q.get() == ']') {
				nestlv = 0;
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WI;
				buf = new StringBuffer();
			} else if(q.get() == ')') {
				q.set(Quadro.WARP2);
				q.west();
				buf = new StringBuffer();
				etat = S.WP_W1;
			} else if(q.get() == '`') {
				q.set(Quadro.E2);
				q.west();
				buf = new StringBuffer();
				etat = S.AR_WG;
			} else if(q.get() == '$') {
				action.setEdgeEnd(q);
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WS;
			} else if(q.get() >= '0' && q.get() <= '9') {
				buf = new StringBuffer().append((char)q.get());
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWN1;
			} else if((q.get() >= 'a' && q.get() <= 'f') ||
					(q.get() >= 'A' && q.get() <= 'F')) {
				buf = new StringBuffer().append((char)q.get());
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWN0;
			} else if(q.get() == '*' || q.get() == '@') {
				if(q.getScratch() != null) {
					throw new NinaException("notjoin");
				} else {
					action.link(q, null);
					action.setAccept(q.get() == '@');
					q.setScratch(Integer.valueOf(q.get()));
					etat = S.ONS_0;
				}
			} else if(q.isLetter() || q.isDigit()) {
				chr = q.get();
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WS;
			} else if(q.isArrow2() || q.isArrow3()) {
				q.east();
				etat = S.AR_ZN;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else if(q.get() == Quadro.DONE) {
				action.link(q, q.getScratch());
				q.east();
				etat = S.ARR_E;
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case ARWN0:
			if((q.get() >= '0' && q.get() <= '9') ||
					(q.get() >= 'a' && q.get() <= 'f') ||
					(q.get() >= 'A' && q.get() <= 'F')) {
				buf.append((char)q.get());
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWN1;
			} else {
				chr = buf.charAt(0);
				buf = new StringBuffer();
				etat = S.AR_WS;
			}
			break;
		case ARWN1:
			if((q.get() >= '0' && q.get() <= '9') ||
					(q.get() >= 'a' && q.get() <= 'f') ||
					(q.get() >= 'A' && q.get() <= 'F')) {
				buf.append((char)q.get());
				q.set(Quadro.E2);
				q.west();
			} else if(q.get() == 'x' || q.get() == 'X') {
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWN2;
			} else if(buf.reverse().charAt(0) != '0') {
				try {
					chr = Integer.parseInt(buf.toString(), 10);
				} catch(NumberFormatException e) {
					throw new NinaException(this, "invalidnumber");
				}
				buf = new StringBuffer();
				etat = S.AR_WS;
			} else {
				try {
					chr = Integer.parseInt(buf.toString(), 8);
				} catch(NumberFormatException e) {
					throw new NinaException(this, "invalidnumber");
				}
				buf = new StringBuffer();
				etat = S.AR_WS;
			}
			break;
		case ARWN2:
			if(q.get() == '0') {
				try {
					chr = Integer.parseInt(buf.reverse().toString(),
							16);
				} catch(NumberFormatException e) {
					throw new NinaException(this, "invalidnumber");
				}
				buf = new StringBuffer();
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WS;
			} else {
				throw new NinaException(this, "invalidnumber");
			}
			break;
		case AR_ZN:
			q.set('<');
			q.north();
			etat = S.FR_N;
			break;
		case AR_WQ:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidquote");
			} else if(q.get() == quote) {
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_Wq;
			} else if(q.get() == '\\') {
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_Wy;
			} else if(q.get() == 'n') {
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_Wn;
			} else if(q.get() == 'r') {
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_Wr;
			} else if(q.get() == 't') {
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_Wt;
			} else if(q.get() == '0') {
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_W0;
			} else if(q.get() == '}') {
				bf2 = new StringBuffer();
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWD1;
			} else if(q.get() >= 0) {
				buf.append((char)q.get());
				q.set(Quadro.E2);
				q.west();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidquote");
			}
			break;
		case AR_Wq:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidquote");
			} else if(q.get() == '\\') {
				buf.append((char)quote);
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WQ;
			} else if(q.get() >= 0) {
				chr = -1;
				etat = S.AR_WS;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidquote");
			}
			break;
		case AR_Wy:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidquote");
			} else if(q.get() == quote) {
				buf.append('\\');
				chr = -1;
				q.set(Quadro.E2);  q.west();
				etat = S.AR_WS;
			} else if(q.get() >= 0) {
				if(q.get() != '\\') {
					buf.append('\\');
				}
				buf.append((char)q.get());
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WQ;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidquote");
			}
			break;
		case AR_Wn:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidquote");
			} else if(q.get() == quote) {
				buf.append('n');
				chr = -1;
				q.set(Quadro.E2);  q.west();
				etat = S.AR_WS;
			} else if(q.get() >= 0) {
				if(q.get() != '\\') {
					buf.append('n');
					buf.append((char)q.get());
				} else {
					buf.append('\n');
				}
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WQ;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidquote");
			}
			break;
		case AR_Wr:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidquote");
			} else if(q.get() == quote) {
				buf.append('r');
				chr = -1;
				q.set(Quadro.E2);  q.west();
				etat = S.AR_WS;
			} else if(q.get() >= 0) {
				if(q.get() != '\\') {
					buf.append('r');
					buf.append((char)q.get());
				} else {
					buf.append('\r');
				}
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WQ;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidquote");
			}
			break;
		case AR_Wt:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidquote");
			} else if(q.get() == quote) {
				buf.append('t');
				chr = -1;
				q.set(Quadro.E2);  q.west();
				etat = S.AR_WS;
			} else if(q.get() >= 0) {
				if(q.get() != '\\') {
					buf.append('t');
					buf.append((char)q.get());
				} else {
					buf.append('\t');
				}
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WQ;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidquote");
			}
			break;
		case AR_W0:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidquote");
			} else if(q.get() == quote) {
				buf.append('0');
				chr = -1;
				q.set(Quadro.E2);  q.west();
				etat = S.AR_WS;
			} else if(q.get() >= 0) {
				if(q.get() != '\\') {
					buf.append('0');
					buf.append((char)q.get());
				} else {
					buf.append('\0');
				}
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WQ;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidquote");
			}
			break;
		case ARWD1:
			if(q.get() == '{') {
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWD2;
			} else if(Character.isJavaIdentifierPart(q.get())) {
				bf2.appendCodePoint(q.get());
				q.set(Quadro.E2);
				q.west();
			} else {
				buf.append('}');
				buf.append(bf2);
				etat = S.AR_WQ;
			}
			break;
		case ARWD2:
			if(q.get() == '$') {
				bt = new StringBuffer(
						getParameter(bf2.reverse().toString()));
				buf.append(bt.reverse());
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WQ;
			} else {
				buf.append('}');
				buf.append(bf2);
				buf.append('{');
				etat = S.AR_WQ;
			}
			break;
		case AR_WR:
			lst = new ArrayList<String>();
			if(q.get() == ')') {
				bf2 = new StringBuffer();
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWR2;
			} else {
				bf2 = null;
				etat = S.ARWR1;
			}
			break;
		case ARWR1:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidsubfa");
			} else if(q.get() == '{') {
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWR5;
			} else if(q.get() >= 0) {
				buf.append((char)q.get());
				q.set(Quadro.E2);
				q.west();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidsubfa");
			}
			break;
		case ARWR2:
			if(q.get() == '(') {
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWR1;
			} else if(q.get() == ',') {
				lst.add(bf2.reverse().toString());
				bf2 = new StringBuffer();
				q.set(Quadro.E2);
				q.west();
			} else if(q.get() == '\'') {
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWR3;
			} else if(q.get() == '"') {
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWR4;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidsubfa");
			}
			break;
		case ARWR3:
			if(q.get() == '\'') {
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWR2;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidsubfa");
			}
			break;
		case ARWR4:
			if(q.get() == '"') {
				q.set(Quadro.E2);
				q.west();
				etat = S.ARWR2;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidsubfa");
			}
			break;
		case ARWR5:
			if(q.get() == '$') {
				metBordLabel(buf.reverse().toString());
				q.set(Quadro.E2);
				q.west();
			} else {
				if(bf2 != null) {
					lst.add(bf2.toString());  bf2 = null;
				}

				mp = new HashMap<String, String>();
				for(int i = 1; i <= lst.size(); i++) {
					mp.put(i + "", lst.get(lst.size() - i));
				}
				metBordRes(buf.reverse().toString(), mp);
			}
			lst = null;
			etat = S.AR_W;
			break;
		case AR_WI:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidchrst");
			} else if(q.get() == '[' && nestlv-- <= 0) {
				q.set(Quadro.E2);  q.west();
				etat = S.AR_Wi;
			} else if(q.get() == ']') {
				q.set(Quadro.E2);  q.west();
				etat = S.ARWi2;
			} else if(q.get() >= 0) {
				buf.append((char)q.get());
				q.set(Quadro.E2);  q.west();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);  q.west();
			} else {
				throw new NinaException(this, "invalidchrst");
			}
			break;
		case AR_Wi:
			if(q.get() == '\\') {
				buf.append('\\');  buf.append('[');
				q.set(Quadro.E2);  q.west();
				etat = S.AR_WI;
			} else {
				metBordCharset(buf.reverse().toString());
				etat = S.AR_W;
			}
			break;
		case ARWi2:
			if(q.get() == '\\') {
				buf.append('\\');  buf.append(']');
				q.set(Quadro.E2);  q.west();
				etat = S.AR_WI;
			} else {
				nestlv++;
				buf.append(']');
				etat = S.AR_WI;
			}
			break;
		case AR_WG:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidregex");
			} else if(q.get() == '`') {
				q.set(Quadro.E2);  q.west();
				etat = S.AR_Wg;
			} else if(q.get() >= 0) {
				buf.append((char)q.get());
				q.set(Quadro.E2);
				q.west();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidregex");
			}
			break;
		case AR_Wg:
			if(q.get() == '\\') {
				buf.append('`');
				q.set(Quadro.E2);  q.west();
				etat = S.AR_WG;
			} else {
				try {
					dm = new NFAState() {};
					nz = RegexpParser.parse(buf.reverse().toString(), dm);
					metBordNFA(nz);
				} catch (RegexParseException e) {
					throw new NinaException(this, "invalidregex");
				}
				etat = S.AR_W;
			}
			break;
		case AR_WS:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidmealy");
			} else if(q.get() == '/' || q.get() == '#' ||
					q.get() == '%') {
				if(chr >= 0) {
					buf = new StringBuffer().append((char)chr);
				}
				chr = q.get();
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WM;
			} else if(chr < 0) {
				metBord(buf.reverse().toString(), quote);
				etat = S.AR_W;
			} else {
				metBord((char)chr);
				etat = S.AR_W;
			}
			break;
		case AR_WM:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidmealy");
			} else if(q.isWhitespace()) {
				q.south().east();
				etat = S.AR_S;
			} else if(q.get() == '\'') {
				metmealy();
				q.set(Quadro.E2);
				q.west();
				buf = new StringBuffer();
				etat = S.AR_WX;
			} else if(q.get() == '}') {
				metmealy();
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WR;
				buf = new StringBuffer();
			} else if(q.get() == ']') {
				metmealy();
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_WI;
				buf = new StringBuffer();
			} else if(q.get() == ')') {
				metmealy();
				q.set(Quadro.WARP2);
				q.west();
				buf = new StringBuffer();
				etat = S.WP_W1;
			} else if(q.get() == '.') {
				metmealy();
				q.setEdge(CharSets.ALL_CHAR);
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_W;
			} else if(q.get() >= 0) {
				metmealy();
				metBord((char)q.get());
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_W;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidmealy");
			}
			break;
		case AR_WX:
			if(q.isBlankX()) {
				throw new NinaException(this, "invalidmealy");
			} else if(q.get() == '\'') {
				metBord(buf.reverse().toString(), quote);
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_W;
			} else if(q.get() >= 0) {
				buf.append((char)q.get());
				q.set(Quadro.E2);
				q.west();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.set(Quadro.E2);
				q.west();
			} else {
				throw new NinaException(this, "invalidmealy");
			}
			break;
		case WP_W1:
			if(q.get() == '(') {
				buf.reverse();
				q.set(Quadro.WARP2);
				etat = S.TOJX1;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.west();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.west();
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case F2_W:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.west();
			} else if(q.isDone()) {
				q.east();
				etat = S.FRR_E;
			} else {
				q.east();
				etat = S.F2_N;
			}
			break;
		case F2_N:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.north();
			} else if(q.isDone()) {
				q.south();
				etat = S.FRR_S;
			} else {
				q.south();
				etat = S.LBLE;
			}
			break;
		case F3_W:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.west();
			} else {
				q.east();
				etat = S.LBLE;
			}
			break;
		case F3_N:
			if(q.isFrame() || q.isArrow() || q.isEntry()) {
				q.north();
			} else {
				q.south();
				etat = S.F3_W;
			}
			break;
		case FRR_S:
			if(q.isFrame() || q.isArrow() || q.isDone()) {
				q.set(Quadro.DONE);
				q.south();
			} else if(q.isEntry()) {
				q.set(Quadro.DONE);
				q.west();
				etat = S.ARR_W;
			} else {
				q.north().east();
				etat = S.FRR_E;
			}
			break;
		case FRR_E:
			if(q.isFrame() || q.isArrow() || q.isDone()) {
				q.set(Quadro.DONE);
				q.east();
			} else if(q.isEntry()) {
				q.set(Quadro.DONE);
				q.south();
				etat = S.ARR_S;
			} else {
				q.north().west();
				etat = S.FRR_N;
			}
			break;
		case FRR_N:
			if(q.isFrame() || q.isArrow() || q.isDone()) {
				q.set(Quadro.DONE);
				q.north();
			} else if(q.isEntry()) {
				q.set(Quadro.DONE);
				q.east();
				etat = S.ARR_E;
			} else {
				q.south().west();
				etat = S.FRR_W;
			}
			break;
		case FRR_W:
			if(q.isFrame() || q.isArrow()) {
				q.set(Quadro.DONE);
				q.west();
			} else if(q.isEntry()) {
				q.set(Quadro.DONE);
				q.north();
				etat = S.ARR_N;
			} else if(q.getVisiting() != null) {
				buf = new StringBuffer(q.getVisiting());
				q.setVisiting(null);
				etat = S.TOIX2;
			} else if(enddead) {
				etat = S.DED04;
			} else {
				etat = S.DED01;
			}
			break;
		case DED01:
			if(q.isBlankX()) {
				q.east();
				etat = S.DED02;
			} else {
				q.west();
			}
			break;
		case DED02:
			if(q.isBlankY() || q.get() == '#') {
				q.south();
				etat = S.DED03;
			} else {
				q.north();
			}
			break;
		case DED03:
			if(q.isBlankY()) {
				q.north();
				etat = S.DED05;
			} else if(q.isBlankX()) {
				q.cr();
			} else if(!DEADSYM.equals(q.getLabel())) {
				q.east();
			} else if(q.getScratch() != null) {
				etat = S.DED04;
			} else {
				enddead = true;
				action.setVertex(action.createState(q));
				etat = S.LBLE;
			}
			break;
		case DED04:
			if(q.isBlankX()) {
				q.east();
				etat = S.DED05;
			} else {
				q.west();
			}
			break;
		case DED05:
			if(q.isBlankY() || q.get() == '#') {
				q.south();
				etat = S.DED06;
			} else {
				q.north();
			}
			break;
		case DED06:
			if(q.isBlankY()) {
				return action.accept(q.getName());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.getLabel() == null) {
				q.east();
			} else if(q.getScratch() != null) {
				action.putStateByLabel(q.getLabel(), q.getScratch());
				action.putTypeByLabel(q.getLabel(), q.getLabelType());
				q.east();
			} else {
				action.setVertex(action.createState(q));
				etat = S.LBLE;
			}
			break;
		case ARR_N:
			if(q.get() == Quadro.N2) {
				q.set(Quadro.S3);
				q.north();
				etat = S.ARR_N;
			} else if(q.get() == Quadro.E2) {
				q.set(Quadro.W3);
				q.east();
				etat = S.ARR_E;
			} else if(q.get() == Quadro.S2) {
				q.set(Quadro.N3);
				q.south();
				etat = S.ARR_S;
			} else if(q.get() == Quadro.W2) {
				q.set(Quadro.E3);
				q.west();
				etat = S.ARR_W;
			} else if(q.isBranch()) {
				q.setEdge(((Z)q.getScratch()).edge);
				action.setVertex(((Z)q.getScratch()).vertex);
				q.north();
				etat = S.BR_N;
			} else if(q.isArrow()) {
				action.setVertex(q.getScratch());
				q.west();
				etat = S.FR_W;
			} else if(q.isDone()) {
				q.east();
				etat = S.FRR_E;
			} else if(q.isArrow3()) {
				q.south();
				etat = S.ARRZW;
			} else if(q.get() == '*' || q.get() == '@') {
				q.west();
				etat = S.ONS_W;
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case ARRZW:
			q.set(Quadro.DONE);
			etat = S.FRR_W;
			break;
		case ARR_E:
			if(q.get() == Quadro.N2) {
				q.set(Quadro.S3);
				q.north();
				etat = S.ARR_N;
			} else if(q.get() == Quadro.E2) {
				q.set(Quadro.W3);
				q.east();
				etat = S.ARR_E;
			} else if(q.get() == Quadro.S2) {
				q.set(Quadro.N3);
				q.south();
				etat = S.ARR_S;
			} else if(q.get() == Quadro.W2) {
				q.set(Quadro.E3);
				q.west();
				etat = S.ARR_W;
			} else if(q.get() == Quadro.WARP2) {
				q.set(Quadro.WARP3);
				q.east();
				buf = new StringBuffer();
				etat = S.WP_E2;
			} else if(q.isBranch()) {
				q.setEdge(((Z)q.getScratch()).edge);
				action.setVertex(((Z)q.getScratch()).vertex);
				q.north();
				etat = S.BR_N;
			} else if(q.isArrow()) {
				action.setVertex(q.getScratch());
				q.north();
				etat = S.FR_N;
			} else if(q.isDone()) {
				q.south();
				etat = S.FRR_S;
			} else if(q.isArrow3()) {
				q.west();
				etat = S.ARRZN;
			} else if(q.get() == '*' || q.get() == '@') {
				q.north();
				etat = S.ONS_n;
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case WP_E2:
			if(q.get() == Quadro.WARP2) {
				q.set(Quadro.WARP3);
				etat = S.TOIX2;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.east();
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case ARRZN:
			q.set(Quadro.DONE);
			etat = S.FRR_N;
			break;
		case ARR_S:
			if(q.get() == Quadro.N2) {
				q.set(Quadro.S3);
				q.north();
				etat = S.ARR_N;
			} else if(q.get() == Quadro.E2) {
				q.set(Quadro.W3);
				q.east();
				etat = S.ARR_E;
			} else if(q.get() == Quadro.S2) {
				q.set(Quadro.N3);
				q.south();
				etat = S.ARR_S;
			} else if(q.get() == Quadro.W2) {
				q.set(Quadro.E3);
				q.west();
				etat = S.ARR_W;
			} else if(q.isBranch()) {
				q.setEdge(((Z)q.getScratch()).edge);
				action.setVertex(((Z)q.getScratch()).vertex);
				q.north();
				etat = S.BR_N;
			} else if(q.isArrow()) {
				action.setVertex(q.getScratch());
				q.east();
				etat = S.FR_E;
			} else if(q.isDone()) {
				q.west();
				etat = S.FRR_W;
			} else if(q.isArrow3()) {
				q.north();
				etat = S.ARRZE;
			} else if(q.get() == '*' || q.get() == '@') {
				q.east();
				etat = S.ONS_E;
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case ARRZE:
			q.set(Quadro.DONE);
			etat = S.FRR_S;
			break;
		case ARR_W:
			if(q.get() == Quadro.N2) {
				q.set(Quadro.S3);
				q.north();
				etat = S.ARR_N;
			} else if(q.get() == Quadro.E2) {
				q.set(Quadro.W3);
				q.east();
				etat = S.ARR_E;
			} else if(q.get() == Quadro.S2) {
				q.set(Quadro.N3);
				q.south();
				etat = S.ARR_S;
			} else if(q.get() == Quadro.W2) {
				q.set(Quadro.E3);
				q.west();
				etat = S.ARR_W;
			} else if(q.get() == Quadro.WARP2) {
				q.set(Quadro.WARP3);
				q.west();
				buf = new StringBuffer();
				etat = S.WP_W2;
			} else if(q.isBranch()) {
				q.setEdge(((Z)q.getScratch()).edge);
				action.setVertex(((Z)q.getScratch()).vertex);
				q.north();
				etat = S.BR_N;
			} else if(q.isArrow()) {
				action.setVertex(q.getScratch());
				q.south();
				etat = S.FR_S;
			} else if(q.isDone()) {
				q.north();
				etat = S.FRR_N;
			} else if(q.isArrow3()) {
				q.east();
				etat = S.ARRZS;
			} else if(q.get() == '*' || q.get() == '@') {
				q.south();
				etat = S.ONS_S;
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case WP_W2:
			if(q.get() == Quadro.WARP2) {
				buf.reverse();
				q.set(Quadro.WARP3);
				etat = S.TOIX2;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.west();
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case ARRZS:
			q.set(Quadro.DONE);
			etat = S.FRR_S;
			break;
		case BR_N:
			if(q.get() == '|') {
				q.set(Quadro.S2);
				q.north();
				etat = S.AR_N;
			} else if(q.get() == '\\') {
				q.set(Quadro.S2);
				q.west();
				etat = S.AR_W;
			} else if(q.get() == '/') {
				q.set(Quadro.S2);
				q.east();
				etat = S.AR_E;
			} else if(q.get() == '^') {
				action.link(q, o = q.getScratch());
				if(o != null) {
					q.set(Quadro.FRAME_N);
					q.south();
					etat = S.ARR_S;
				} else {
					q.set(Quadro.ENTRY);
					etat = S.F2_W;
				}
			} else if(q.isBranchN()) {
				q.setScratch(new Z(action.getVertex(), q.getEdge()));
				q.set(Quadro.putWedgeN(q.get()));
				q.north();
				etat = S.BR_N;
			} else {
				q.south();
				q.set(Quadro.putWedgeE(q.get()));
				q.east();
				etat = S.BR_E;
			}
			break;
		case BR_E:
			if(q.get() == '-') {
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_E;
			} else if(q.get() == '\\') {
				q.set(Quadro.W2);
				q.south();
				etat = S.AR_S;
			} else if(q.get() == '/') {
				q.set(Quadro.W2);
				q.north();
				etat = S.AR_N;
			} else if(q.get() == '>') {
				action.link(q, o = q.getScratch());
				if(o != null) {
					q.set(Quadro.FRAME_N);
					q.west();
					etat = S.ARR_W;
				} else {
					q.set(Quadro.ENTRY);
					etat = S.F2_N;
				}
			} else if(q.isBranchE()) {
				q.setScratch(new Z(action.getVertex(), q.getEdge()));
				q.set(Quadro.putWedgeN(q.get()));
				q.north();
				etat = S.BR_N;
			} else {
				q.west();
				q.set(Quadro.putWedgeS(q.get()));
				q.south();
				etat = S.BR_S;
			}
			break;
		case BR_S:
			if(q.get() == '|') {
				q.set(Quadro.N2);
				q.south();
				etat = S.AR_S;
			} else if(q.get() == '\\') {
				q.set(Quadro.N2);
				q.east();
				etat = S.AR_E;
			} else if(q.get() == '/') {
				q.set(Quadro.N2);
				q.west();
				etat = S.AR_W;
			} else if(q.get() == 'v') {
				action.link(q, o = q.getScratch());
				if(o != null) {
					q.set(Quadro.FRAME_N);
					q.north();
					etat = S.ARR_N;
				} else {
					q.set(Quadro.ENTRY);
					etat = S.F3_W;
				}
			} else if(q.isBranchS()) {
				q.setScratch(new Z(action.getVertex(), q.getEdge()));
				q.set(Quadro.putWedgeN(q.get()));
				q.north();
				etat = S.BR_N;
			} else {
				q.north();
				q.set(Quadro.putWedgeW(q.get()));
				q.west();
				etat = S.BR_W;
			}
			break;
		case BR_W:
			if(q.get() == '-') {
				q.set(Quadro.E2);
				q.west();
				etat = S.AR_W;
			} else if(q.get() == '\\') {
				q.set(Quadro.E2);
				q.north();
				etat = S.AR_N;
			} else if(q.get() == '/') {
				q.set(Quadro.E2);
				q.south();
				etat = S.AR_S;
			} else if(q.get() == '<') {
				action.link(q, o = q.getScratch());
				if(o != null) {
					q.set(Quadro.FRAME_N);
					q.east();
					etat = S.ARR_E;
				} else {
					q.set(Quadro.ENTRY);
					etat = S.F3_N;
				}
			} else if(q.isBranchW()) {
				q.setScratch(new Z(action.getVertex(), q.getEdge()));
				q.set(Quadro.putWedgeN(q.get()));
				q.north();
				etat = S.BR_N;
			} else {
				q.east().north();
				etat = S.BR2_N;
			}
			break;
		case BR2_N:
			if(q.get() == Quadro.N2) {
				q.set(Quadro.S3);
				q.north();
				etat = S.ARR_N;
			} else if(q.isWedgeN()) {
				q.east();
				etat = S.BR_E;
			} else if(q.isArrow()) {
				action.setVertex(q.getScratch());
				q.west();
				etat = S.FR_W;
			} else {
				q.south().east();
				etat = S.BR2_E;
			}
			break;
		case BR2_E:
			if(q.get() == Quadro.E2) {
				q.set(Quadro.W3);
				q.east();
				etat = S.ARR_E;
			} else if(q.isWedgeE()) {
				q.south();
				etat = S.BR_S;
			} else if(q.isArrow()) {
				action.setVertex(q.getScratch());
				q.north();
				etat = S.FR_N;
			} else {
				q.west().south();
				etat = S.BR2_S;
			}
			break;
		case BR2_S:
			if(q.get() == Quadro.S2) {
				q.set(Quadro.N3);
				q.south();
				etat = S.ARR_S;
			} else if(q.isWedgeS()) {
				q.west();
				etat = S.BR_W;
			} else if(q.isArrow()) {
				action.setVertex(q.getScratch());
				q.east();
				etat = S.FR_E;
			} else {
				q.north().west();
				etat = S.BR2_W;
			}
			break;
		case BR2_W:
			if(q.get() == Quadro.W2) {
				q.set(Quadro.E3);
				q.west();
				etat = S.ARR_W;
			} else if(q.isWedgeW()) {
				q.north();
				etat = S.BR2_N;
			} else if(q.isArrow()) {
				action.setVertex(q.getScratch());
				q.south();
				etat = S.FR_S;
			} else {
				throw new NinaException(this, "invalidedge");
			}
			break;
		case TOIX1:
			regX = q.getX();
			regY = q.getY();
			etat = S.TOIx1;
			todir = Quadro.Direction.WEST;
			break;
		case TOJX1:
			regX = q.getX();
			regY = q.getY();
			etat = S.TOIx1;
			todir = Quadro.Direction.EAST;
			break;
		case TOIx1:
			if(q.isBlankX()) {
				q.east();
				etat = S.TOIY1;
			} else {
				q.west();
			}
			break;
		case TOIY1:
			if(q.isBlankY() || q.get() == '#') {
				q.south();
				etat = S.SER1E;
			} else {
				q.north();
			}
			break;
		case SER1E:
			if(q.isBlankY()) {
				q.north();
				etat = S.TORY1;
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.getLabel() == null ||
					!q.getLabel().equals(buf.toString())) {
				q.east();
			} else {
				action.link(q, o = q.getScratch());
				if(o != null) {
//					etat = S.TOIX2;
					q.setPosition(regX, regY);
					q.set(Quadro.WARP3);
					q.west();
					etat = S.RETP1;
				} else {
					q.setVisiting(buf.toString());
					etat = S.LBLE;
				}
			}
			break;
		case RETP1:
			// return position
			if(q.get() == Quadro.WARP2) {
				q.set(Quadro.WARP3);
//				q.west();
				q.move(todir);
				etat = todir.equals(Quadro.Direction.WEST) ?
						S.ARR_W : S.ARR_E;
			} else if(q.isBlankX()) {
				throw new NinaException(this, "labelnotfound",
						buf.toString());
			} else {
//				q.west();
				q.move(todir);
			}
			break;
		case TORY1:
			if(q.isBlankY() || q.get() == '#') {
				q.south();
				etat = S.SER11;
			} else {
				q.north();
			}
			break;
		case SER11:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.get() == '\'') {
				q.east();
				etat = S.SER1q;
			} else if(q.get() == '[') {
				q.east();
				etat = S.SER1c;
			} else if(q.get() == '`') {
				q.east();
				etat = S.SER1r;
			} else if(q.get() == '(') {
				q.east();
				etat = S.SER1F;
				bf2 = new StringBuffer();
			} else if(q.get() == '-') {
				q.east();
				etat = S.SER1W;
			} else {
				q.east();
			}
			break;
		case SER1q:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.get() == '\\') {
				q.east();
				etat = S.SER1b;
			} else if(q.get() == '\'') {
				q.east();
				etat = S.SER11;
			} else {
				q.east();
			}
			break;
		case SER1c:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.get() == ']') {
				q.east();
				etat = S.SER11;
			} else {
				q.east();
			}
			break;
		case SER1r:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.get() == '`') {
				q.east();
				etat = S.SER11;
			} else {
				q.east();
			}
			break;
		case SER1b:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
				etat = S.SER1q;
			} else {
				q.east();
				etat = S.SER1q;
			}
			break;
		case SER1F:
			if(q.get() == ')') {
				if(buf.toString().equals(bf2.toString())) {
					q.west();
					etat = S.SER1G;
				} else {
					etat = S.SER11;
				}
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.east();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			}
			break;
		case SER1G:
			if(q.get() == '(') {
				q.set(Quadro.WARP2);
				q.east();
				etat = S.SER1H;
			} else if(q.get() >= 0) {
				q.west();
			} else {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			}
			break;
		case SER1H:
			if(q.get() == ')') {
				q.set(Quadro.WARP2);
				q.east();
				etat = S.AR_E;
			} else if(q.get() >= 0) {
				q.east();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			}
			break;
		case SER1W:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.get() == '\'') {
				q.east();
				etat = S.SER1Q;
			} else if(q.get() == '[') {
				q.east();
				etat = S.SER1C;
			} else if(q.get() == '`') {
				q.east();
				etat = S.SER1R;
			} else if(q.get() == '(') {
				q.east();
				etat = S.SER1X;
				bf2 = new StringBuffer();
			} else if(q.get() != '-') {
				q.east();
				etat = S.SER11;
			} else {
				q.east();
			}
			break;
		case SER1Q:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.get() == '\\') {
				q.east();
				etat = S.SER1B;
			} else if(q.get() == '\'') {
				q.east();
				etat = S.SER1W;
			} else {
				q.east();
			}
			break;
		case SER1C:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.get() == ']') {
				q.east();
				etat = S.SER1W;
			} else {
				q.east();
			}
			break;
		case SER1R:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.get() == '`') {
				q.east();
				etat = S.SER1W;
			} else {
				q.east();
			}
			break;
		case SER1B:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
				etat = S.SER1Q;
			} else {
				q.east();
				etat = S.SER1Q;
			}
			break;
		case SER1X:
			if(q.get() == ')') {
				if(buf.toString().equals(bf2.toString())) {
					q.set(Quadro.WARP2);
					q.west();
					etat = S.SER1Y;
				} else {
					etat = S.SER1W;
				}
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.east();
			} else {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			}
			break;
		case SER1Y:
			if(q.get() == '(') {
				q.set(Quadro.WARP2);
				q.west();
				etat = S.AR_W;
			} else if(q.get() >= 0) {
				q.west();
			} else {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			}
			break;
		case TOIX2:
			if(q.isBlankX()) {
				q.east();
				etat = S.TOIY2;
			} else {
				q.west();
			}
			break;
		case TOIY2:
			if(q.isBlankY() || q.get() == '#') {
				q.south();
				etat = S.SER2E;
			} else {
				q.north();
			}
			break;
		case SER2E:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.get() == Quadro.WARP2) {
				q.east();
				etat = S.SER2F;
				bf2 = new StringBuffer();
			} else if(q.get() == Quadro.W2) {
				q.east();
				etat = S.SER2W;
			} else {
				q.east();
			}
			break;
		case SER2F:
			if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.east();
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else if(q.get() != Quadro.WARP2) {
				q.east();
				etat = S.SER2E;
			} else if(buf.toString().equals(bf2.toString())) {
				q.west();
				etat = S.SER2G;
			} else {
				etat = S.SER2E;
			}
			break;
		case SER2G:
			if(q.get() >= 0) {
				q.west();
			} else if(q.get() == Quadro.WARP2) {
				q.set(Quadro.WARP3);
				q.east();
				etat = S.SER2H;
			} else if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			}
			break;
		case SER2H:
			if(q.get() >= 0) {
				q.east();
			} else if(q.get() == Quadro.WARP2) {
				q.set(Quadro.WARP3);
				q.east();
				etat = S.ARR_E;
			} else {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			}
			break;
		case SER2W:
			if(q.isBlankY()) {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			} else if(q.isBlankX()) {
				q.cr();
			} else if(q.get() == Quadro.WARP2) {
				q.east();
				etat = S.SER2X;
				bf2 = new StringBuffer();
			} else if(q.get() != Quadro.W2) {
				q.east();
				etat = S.SER2E;
			} else {
				q.east();
			}
			break;
		case SER2X:
			if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.east();
			} else if(q.get() != Quadro.WARP2) {
				q.east();
				etat = S.SER2E;
			} else if(buf.toString().equals(bf2.toString())) {
				q.set(Quadro.WARP3);
				q.west();
				etat = S.SER2Y;
			} else {
				etat = S.SER2E;
			}
			break;
		case SER2Y:
			if(q.get() >= 0) {
				q.west();
			} else if(q.get() == Quadro.WARP2) {
				q.set(Quadro.WARP3);
				q.west();
				etat = S.ARR_W;
			} else {
				throw new NinaException(
						this, "labelnotfound", buf.toString());
			}
			break;
		case ONS_0:
			q.north();
			etat = S.ONS_N;
			break;
		case ONS_N:
			if(q.get() == '|' || q.get() == '/' || q.get() == '\\' ||
					q.isBranchN()) {
				etat = S.AR_N;
			} else {
				q.south().east();
				etat = S.ONS_E;
			}
			break;
		case ONS_E:
			if(q.get() == '-' || q.get() == '/' || q.get() == '\\' ||
					q.isBranchE()) {
				etat = S.AR_E;
			} else {
				q.south().west();
				etat = S.ONS_S;
			}
			break;
		case ONS_S:
			if(q.get() == '|' || q.get() == '/' || q.get() == '\\' ||
					q.isBranchS()) {
				etat = S.AR_S;
			} else {
				q.north().west();
				etat = S.ONS_W;
			}
			break;
		case ONS_W:
			if(q.get() == '-' || q.get() == '/' || q.get() == '\\' ||
					q.isBranchE()) {
				etat = S.AR_E;
			} else {
				q.north().east();
				etat = S.ONS_n;
			}
			break;
		case ONS_n:
			if(q.get() == Quadro.N2 || q.isBranch()) {
				etat = S.ARR_N;
			} else {
				q.south().east();
				etat = S.ONS_e;
			}
			break;
		case ONS_e:
			if(q.get() == Quadro.E2 || q.isBranch()) {
				etat = S.ARR_E;
			} else {
				q.south().west();
				etat = S.ONS_s;
			}
			break;
		case ONS_s:
			if(q.get() == Quadro.S2 || q.isBranch()) {
				etat = S.ARR_S;
			} else {
				q.north().west();
				etat = S.ONS_w;
			}
			break;
		case ONS_w:
			if(q.get() == Quadro.W2 || q.isBranch()) {
				etat = S.ARR_W;
			} else {
				throw new RuntimeException();
			}
			break;
		}

		counter = z == etat ? counter + 1 : 0;
		if(counter > 100000) {
			throw new RuntimeException(z.toString());
		}
		return null;
	}

	/**
	 * 
	 * @param s
	 * @return
	 */
	public String getPragma(String s) {
		return pragmas.get(s);
	}

	/**
	 * 
	 * @param pr
	 */
	public void printTrace(PrintStream pr) {
		pr.println(etat);
		pr.println(q.toString());
		pr.println(q.get() < 0 ? q.get() : (char)q.get());
	}

}
