@Override
	public String[] parseEval(String evaluable) throws ScriptParseException
	{
		final int STATE_MAIN=0;
		final int STATE_INFUNCTION=1;
		final int STATE_INFUNCQUOTE=2;
		final int STATE_POSTFUNCTION=3;
		final int STATE_POSTFUNCEVAL=4;
		final int STATE_POSTFUNCQUOTE=5;
		final int STATE_MAYFUNCTION=6;

		final Vector<String> V=new Vector<String>();
		if((evaluable==null)||(evaluable.trim().length()==0))
			return new String[]{};
		final char[] evalC=evaluable.toCharArray();
		int state=0;
		int dex=0;
		char lastQuote='\0';
		String s=null;
		int depth=0;
		for(int c=0;c<evalC.length;c++)
		{
			switch(state)
			{
			case STATE_MAIN:
			{
				if(Character.isWhitespace(evalC[c]))
				{
					s=new String(evalC,dex,c-dex).trim();
					if(s.length()>0)
					{
						s=s.toUpperCase();
						V.addElement(s);
						dex=c+1;
						if(funcH.containsKey(s))
							state=STATE_MAYFUNCTION;
						else
						if(!connH.containsKey(s))
							throw new ScriptParseException("Unknown keyword: "+s);
					}
				}
				else
				if(Character.isLetter(evalC[c]))
				{ /* move along */
				}
				else
				{
					switch(evalC[c])
					{
					case '!':
					{
						if(c==evalC.length-1)
							throw new ScriptParseException("Bad Syntax on last !");
						V.addElement("NOT");
						dex=c+1;
						break;
					}
					case '(':
					{
						s=new String(evalC,dex,c-dex).trim();
						if(s.length()>0)
						{
							s=s.toUpperCase();
							V.addElement(s);
							V.addElement("(");
							dex=c+1;
							if(funcH.containsKey(s))
								state=STATE_INFUNCTION;
							else
							if(connH.containsKey(s))
								state=STATE_MAIN;
							else
								throw new ScriptParseException("Unknown keyword: "+s);
						}
						else
						{
							V.addElement("(");
							depth++;
							dex=c+1;
						}
						break;
					}
					case ')':
						s=new String(evalC,dex,c-dex).trim();
						if(s.length()>0)
							throw new ScriptParseException("Bad syntax before ) at: "+s);
						if(depth==0)
							throw new ScriptParseException("Unmatched ) character");
						V.addElement(")");
						depth--;
						dex=c+1;
						break;
					default:
						throw new ScriptParseException("Unknown character at: "+new String(evalC,dex,c-dex+1).trim()+": "+evaluable);
					}
				}
				break;
			}
			case STATE_MAYFUNCTION:
			{
				if(evalC[c]=='(')
				{
					V.addElement("(");
					dex=c+1;
					state=STATE_INFUNCTION;
				}
				else
				if(!Character.isWhitespace(evalC[c]))
					throw new ScriptParseException("Expected ( at "+evalC[c]+": "+evaluable);
				break;
			}
			case STATE_POSTFUNCTION:
			{
				if(!Character.isWhitespace(evalC[c]))
				{
					switch(evalC[c])
					{
					case '=': case '>': case '<': case '!':
					{
						if(c==evalC.length-1)
							throw new ScriptParseException("Bad Syntax on last "+evalC[c]);
						if(!Character.isWhitespace(evalC[c+1]))
						{
							s=new String(evalC,c,2);
							if((!signH.containsKey(s))&&(evalC[c]!='!'))
								s=""+evalC[c];
						}
						else
							s=""+evalC[c];
						if(!signH.containsKey(s))
						{
							c=dex-1;
							state=STATE_MAIN;
							break;
						}
						V.addElement(s);
						dex=c+(s.length());
						c=c+(s.length()-1);
						state=STATE_POSTFUNCEVAL;
						break;
					}
					default:
						c=dex-1;
						state=STATE_MAIN;
						break;
					}
				}
				break;
			}
			case STATE_INFUNCTION:
			{
				if(evalC[c]==')')
				{
					V.addElement(new String(evalC,dex,c-dex));
					V.addElement(")");
					dex=c+1;
					state=STATE_POSTFUNCTION;
				}
				else
				if((evalC[c]=='\'')||(evalC[c]=='`'))
				{
					lastQuote=evalC[c];
					state=STATE_INFUNCQUOTE;
				}
				break;
			}
			case STATE_INFUNCQUOTE:
			{
				if(evalC[c]==lastQuote)
					state=STATE_INFUNCTION;
				break;
			}
			case STATE_POSTFUNCQUOTE:
			{
				if(evalC[c]==lastQuote)
				{
					if((V.size()>2)
					&&(signH.containsKey(V.lastElement()))
					&&(V.elementAt(V.size()-2).equals(")")))
					{
						final String sign=V.lastElement();
						V.removeElementAt(V.size()-1);
						V.removeElementAt(V.size()-1);
						final String prev=V.lastElement();
						if(prev.equals("("))
							s=sign+" "+new String(evalC,dex+1,c-dex);
						else
						{
							V.removeElementAt(V.size()-1);
							s=prev+" "+sign+" "+new String(evalC,dex+1,c-dex);
						}
						V.addElement(s);
						V.addElement(")");
						dex=c+1;
						state=STATE_MAIN;
					}
					else
						throw new ScriptParseException("Bad postfunc Eval somewhere");
				}
				break;
			}
			case STATE_POSTFUNCEVAL:
			{
				if(Character.isWhitespace(evalC[c]))
				{
					s=new String(evalC,dex,c-dex).trim();
					if(s.length()>0)
					{
						if((V.size()>1)
						&&(signH.containsKey(V.lastElement()))
						&&(V.elementAt(V.size()-2).equals(")")))
						{
							final String sign=V.lastElement();
							V.removeElementAt(V.size()-1);
							V.removeElementAt(V.size()-1);
							final String prev=V.lastElement();
							if(prev.equals("("))
								s=sign+" "+new String(evalC,dex+1,c-dex);
							else
							{
								V.removeElementAt(V.size()-1);
								s=prev+" "+sign+" "+new String(evalC,dex+1,c-dex);
							}
							V.addElement(s);
							V.addElement(")");
							dex=c+1;
							state=STATE_MAIN;
						}
						else
							throw new ScriptParseException("Bad postfunc Eval somewhere");
					}
				}
				else
				if(Character.isLetterOrDigit(evalC[c]))
				{ /* move along */
				}
				else
				if((evalC[c]=='\'')||(evalC[c]=='`'))
				{
					s=new String(evalC,dex,c-dex).trim();
					if(s.length()==0)
					{
						lastQuote=evalC[c];
						state=STATE_POSTFUNCQUOTE;
					}
				}
				break;
			}
			}
		}
		if((state==STATE_POSTFUNCQUOTE)
		||(state==STATE_INFUNCQUOTE))
			throw new ScriptParseException("Unclosed "+lastQuote+" somewhere");
		if(depth>0)
			throw new ScriptParseException("Unclosed ( somewhere");
		return CMParms.toStringArray(V);
	}