/*
 * 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.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
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.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

public class NinaParser {

	//
	static class Z {

		Object vertex, edge;

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

	}

	//
	private static enum S {
		INIT,  PRAG,  PACK,  MACHN, TYPE,
		OPTN,  OPTV,  OPTQ,  ALIAS, ALI_V, ALI_Q, IMPR, COMNT,
		DEF1,  DEF2,  DEF3,  DEF4,  DEFI1, DEFI2,
		LINIT, LINI2, FI_L1, FI_L2, FI_L3, FI_L4,
		FI_E,  FI_E2, FI_S,  FI_W,  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,
		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,
		AR_WI, AR_Wi, 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, TOIY1,
		SER1E, 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,
	}

	//
	private static final Pattern ANYS = Pattern.compile("\\.([0-9]+)");

	//
	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>();
	Map<String, Object> subfas = new HashMap<String, Object>();
	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;
	private List<String> lst;
	private boolean enddead = false;
	private int nestlv;
	private int pause;
	private int quote;
	private int chr;

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

	//
	private InputStream findLib(String n) {
		File f;

		if((f = new File(n)).isFile()) {
			try {
				return new FileInputStream(f);
			} catch(FileNotFoundException e) {
				throw new RuntimeException(e);
			}
		} else {
			for(String s : libs) {
				f = new File(new File(s), n);
				if(f.isFile()) {
					try {
						return new FileInputStream(f);
					} catch(FileNotFoundException e) {
						throw new RuntimeException(e);
					}
				}
			}
			return null;
		}
	}

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

		try {
			console.print("process", n);
			s = Nina.getFAName(n);
			if((q = this.q.getSubQuadro(n)) != null) {
				q = q.prototype(this.q);
			} else if((in = findLib(n)) != null) {
				q = Quadro.read(s, new InputStreamReader(in));
			} else if((in = NinaLibrary.loadLibrary(n)) != null) {
				q = Quadro.read(s, new InputStreamReader(in));
			} else {
				throw new NinaException("subautomatonnotfound",
						n);
			}
			r = compile(q, action, libs, prms, subs, console, 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,
			Map<String, Object> subs,
			NinaConsole cons,
			int p) {
		NinaParser c = new NinaParser(q, action, prms, subs, cons);
		NinaAction o;

		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);
				}
			}
		} 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,
			Map<String, Object> subs,
			NinaConsole cons) {
		return NinaParser.compile(q,
				null,
				libs != null ? new ArrayList<String>(libs) : null,
				prms,
				subs,
				cons,
				0);
	}

	/**
	 * 
	 * @param q
	 * @param prms
	 * @param subs
	 * @return
	 */
	public static NinaAction complie(Quadro q,
			Map<String, String> prms,
			Map<String, Object> subs,
			NinaConsole cons) {
		return NinaParser.compile(q, null, null, prms, subs, cons, 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) {
		Matcher m;

		if(s.startsWith("ex:")) {
			action.setUserEdge(q, s.substring(3));
		} else if(s.indexOf("$c") >= 0) {
			action.setUserEdge(q, s);
		} else if((m = ANYS.matcher(s)).matches()) {
			action.setEdgeSequence(q, Integer.valueOf(m.group(1)));
		} else {
			action.setEdgeResource(q, this, s, 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 metmealy() {
		action.setMealyEdgeType(chr);
		action.setMealyEdge(buf.reverse().toString());
		chr = -1;
	}

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

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

		switch(etat) {
		case INIT:
			if(q.get() == '#') {
				buf = new StringBuffer();
				q.east();
				etat = S.PRAG;
			} else if(q.get() == '%') {
				q.east();
				etat = S.DEF1;
			} else if(q.isBlankY()) {
				throw new NinaException(this, "unexpectedeof");
			} else if(!q.isBlankX()) {
				etat = S.LINIT;
			}
			break;
		case PRAG:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else if(q.isLetter()) {
				buf.appendCodePoint(q.get());
				q.east();
			} else if(!Character.isWhitespace(q.get())) {
				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("import")) {
				buf = new StringBuffer();
				q.east();
				etat = S.IMPR;
			} else if(buf.toString().equals("alias")) {
				buf = new StringBuffer();
				q.east();
				etat = S.ALIAS;
			} else {
				etat = S.COMNT;
			}
			break;
		case PACK:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else if(q.isLetter() || q.isDigit() || q.get() == '.') {
				buf.appendCodePoint(q.get());
				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.east();
			} else if(q.isLetter() || q.get() == '.') {
				buf.appendCodePoint(q.get());
				q.east();
			} else {
				s = buf.toString().trim();
				pragmas.put("machine", s);
				q.options.put("machine", s);
				if(s.indexOf('.') < 0) {
					s = getClass().getPackage().getName() + "." + s;
				}

				n = (NinaAction)Nina.prendClasse(s);
				t = Nina.getFAName(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(n.getClass())) {
					throw new NinaException(this, "unknownmachine", s);
				}
				etat = S.COMNT;
			}
			break;
		case TYPE:
			s = null;
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else if(q.isLetter() || q.get() == '.') {
				buf.appendCodePoint(q.get());
				q.east();
			} else if((s = buf.toString().trim()).equals("char")) {
				type = Character.TYPE;
				etat = S.COMNT;
			} else if(s.equals("int")) {
				type = Integer.TYPE;
				etat = S.COMNT;
			} else if(s.equals("long")) {
				type = Long.TYPE;
				etat = S.COMNT;
			} else if(s.equals("float")) {
				type = Float.TYPE;
				etat = S.COMNT;
			} else if(s.equals("double")) {
				type = Double.TYPE;
				etat = S.COMNT;
			} else if(s.equals("string")) {
				type = String.class;
				etat = S.COMNT;
			} else if(s.equals("class")) {
				type = Class.class;
				etat = S.COMNT;
			} else {
				type = (Class<?>)Nina.prendClasse(s);
				etat = S.COMNT;
			}
			if(s != null)  pragmas.put("type", q.type = s);
			break;
		case OPTN:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else if(q.get() == '=') {
				bf2 = new StringBuffer();
				q.east();
				etat = S.OPTV;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.east();
			} else {
				q.options.put(buf.toString(), "");
				etat = S.COMNT;
			}
			break;
		case OPTV:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else if(q.get() == '\'') {
				q.east();
				etat = S.OPTQ;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.east();
			} else {
				s = buf.toString();
				if(s.equals("default") && !subfas.containsKey(
						t = Nina.getFAName(bf2.toString()))) {
					subfas.put(t, null);
					compileSubautomaton(t, new DFABuilder(),
							Collections.<String, String>emptyMap(),
							subfas);
				}
				q.options.put(s, bf2.toString());
				etat = S.COMNT;
			}
			break;
		case OPTQ:
			if(q.get() == '\'') {
				q.east();
				etat = S.OPTV;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.east();
			} else {
				throw new NinaException(this, "invalidoption");
			}
			break;
		case ALIAS:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else if(q.get() == '=') {
				bf2 = new StringBuffer();
				q.east();
				etat = S.ALI_V;
			} else if(q.get() >= 0) {
				buf.appendCodePoint(q.get());
				q.east();
			} else {
				q.options.put(buf.toString(), "");
				etat = S.COMNT;
			}
			break;
		case ALI_V:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else if(q.get() == '\'') {
				q.east();
				etat = S.ALI_Q;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.east();
			} else {
				q.options.put(buf.toString(), bf2.toString());
				etat = S.COMNT;
			}
			break;
		case ALI_Q:
			if(q.get() == '\'') {
				q.east();
				etat = S.ALI_V;
			} else if(q.get() >= 0) {
				bf2.appendCodePoint(q.get());
				q.east();
			} else {
				throw new NinaException(this, "invalidalias");
			}
			break;
		case IMPR:
			if(q.get() == Quadro.EQ_TO_LEFT) {
				q.east();
			} else if(q.isLetter() || q.isDigit() || q.get() == '.') {
				buf.appendCodePoint(q.get());
				q.east();
			} else {
				s = buf.toString().trim();
				q.addImports(s);
				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.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(_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_L1;
				}
			} 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_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();
				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 {
				q.east();
				q.setLabel(buf.toString());
				q.setLabelType(bf2.toString());
				buf = new StringBuffer();
				bf2 = new StringBuffer();
				etat = S.FI_E;
			}
			break;
		case FI_L3:
			if(q.get() == '\'') {
				q.set('*');
				etat = S.FI_L1;
			} else if(q.get() == '<') {
				bf2 = new StringBuffer();
				q.set('*');
				q.east();
				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() == '>') {
				q.set('*');
				q.west();
				etat = S.FI_L2;
			} else if(q.get() >= 0) {
				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()) {
				q.transformFrame();
				q.setScratch2(_FRAME2);
				q.south();
			} else {
				q.north();
				etat = S.FI_W;
			}
			break;
		case FI_W:
			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.isFrame() ||
					q.isArrow() || q.isEntry() || q.isDone()) {
				q.transformFrame();
				q.setScratch2(_FRAME2);
				q.north();
			} else {
				q.south();
				q.setScratch2(_FRAME1);
				etat = S.LINIT;
			}
			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()) {
				throw new NinaException(this, "unexpectedeof");
			} 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.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() == '$') {
				action.setEdgeEnd(q);
				q.set(Quadro.W2);
				q.east();
				etat = S.AR_ES;
			} 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.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 {
					nz = RegexpParser.parse(buf.toString());
					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 if(q.get() >= 0) {
//				action.setMealyEdge(q.get());
//				q.set(Quadro.W2);
//				q.east();
//				etat = S.AR_E;
			} 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 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.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.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() == '{') {
				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;
				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, "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 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() >= 0) {
				if(q.get() == ']')  nestlv++;
				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 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 {
					nz = RegexpParser.parse(buf.reverse().toString());
					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.TOIX1;
			} 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.isDone()) {
				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 {
				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 {
				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 {
				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 {
				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:
			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;
				} else {
					etat = S.LBLE;
				}
			}
			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;
		}
		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());
	}

}
