// utf-8

/*	Copyright  (c)	Günter Woigk   2001-2003
  					mailto:kio@little-bat.de

	This file is free software

 	This program is distributed in the hope that it will be useful,
 	but WITHOUT ANY WARRANTY; without even the implied warranty of
 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

 	Permission to use, copy, modify, distribute, and sell this software and
 	its documentation for any purpose is hereby granted without fee, provided
 	that the above copyright notice appear in all copies and that both that
 	copyright notice and this permission notice appear in supporting
 	documentation, and that the name of the copyright holder not be used
 	in advertising or publicity pertaining to distribution of the software
 	without specific, written prior permission. The copyright holder makes no
 	representations about the suitability of this software for any purpose.
 	It is provided "as is" without express or implied warranty.

 	THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 	INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 	EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 	CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 	DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 	TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 	PERFORMANCE OF THIS SOFTWARE.
*/


/*			Attention:
		
			printable text in this file must be UTF-8 encoded!
*/			



#ifdef	TOKEN_PASS			// included from token.cp ?
	#ifdef	_token_h_
		#undef	_token_h_	// then allow multiple inclusion
	#endif
#else
	#define	TOKEN_PASS 1
#endif


#ifndef _token_h_
#define _token_h_


#if TOKEN_PASS==1
	extern	String	Tokenize		( cString& source, long& idx_io );
	extern	uchar*	SkipToken		( uchar* ip );
	extern	uchar*	SkipMatching	( uchar* ip, bool setdist );
	extern	uchar*	Disass			( class Stream* stream, uchar*p, int n );
	extern	String	DisassString	( cString& );
	extern	String	TokenName		( uint t );
	extern	String	TokenSyntax		( uint t );
	extern	String	TokenInfo		( uint t );
	extern	char 	tokenprio[];

	inline	uchar*	SkipIdf			( uchar* ip ) { return ip +3 +ip[1]*ip[2]; }
	extern	uchar*	SkipTerm		( uchar* ip, int prio );

// non-aligned read/write
// penalty for miss-aligned read/write double is ~2000 cycles on MacOSX/G4
// penalty for miss-aligned read/write long is neglectable
// unluckily, there is an error in the GCC for i386 and -O2 optimization
// so only use the work-arounds if required...
	inline void write_double(uchar*p, double f)
	{
#if defined(_POWERPC)
		XXXTRAP(sizeof(double)!=2*sizeof(long));
		((long*)p)[0] = ((long*)&f)[0];		// <-- this also fails on i386 -O2 !!
		((long*)p)[1] = ((long*)&f)[1];		// <-- ""
#else
		*(double*)p = f;
#endif
	}

	inline double read_double(uchar*p)
	{
#if defined(_POWERPC)
		double f;
		((long*)&f)[0] = ((long*)p)[0];		// <-- this fails on i386 -O2
		((long*)&f)[1] = ((long*)p)[1];		// <-- probably due to optimization
		return f;							// <-- f is not yet written when returning here!
#else
		return *(double*)p;
#endif
	}

	#define TOKEN(a,e,b,c,d)	a
	enum{

#elif TOKEN_PASS==2
	#define TOKEN(a,e,b,c,d)	b
	String tokenname[]={

#elif TOKEN_PASS==3
	#define	TOKEN(a,e,b,c,d)	c
	cUTF8Str tokensyntax[]={

#elif TOKEN_PASS==4
	#define	TOKEN(a,e,b,c,d)	d
	cUTF8Str tokeninfo[]={

#elif TOKEN_PASS==5
	#define	TOKEN(a,e,b,c,d)	e
	char tokenprio[]={

#else
	#error Du hast dich verzählt...
#endif


//		i	= identifier/name
//		n	= numeric expression
//		t	= text expression
//		l	= list expression
//		x	= numeric, text or list expression
//		v	= variable reference
//		[]	= optional part
//		|	= separates options
//		[,…]= optional repetition, separated by komma


// ----	tokens with immediate arguments -----------------------------------

// number constant: 8-byte-double follows
TOKEN(tNUM,		pAny,		"tNUM",			"12.34e56|$1234|'abc'",
"internal representation of numeric literals." ),

// number constant: 0  ((null))
TOKEN(tNUM0,	pAny,		"0",			"0",
"internal representation of numeric literal '0'." ),

// number constant: 1  ((one))
TOKEN(tNUM1,	pAny,		"1",			"1",
"internal representation of numeric literal '1'." ),

// number constant: signed short int follows
TOKEN(tSHORT,	pAny,		"tSHORT",		"1234|$123|'ab'",
"internal representation of small numeric literals." ),

// number constant: signed byte follows
TOKEN(tBYTE,	pAny,		"tBYTE",		"12|$12|'a'",
"internal representation of small numeric literals." ),

// string constant: dc.b csz, dc.b chars, dc.s text follows
TOKEN(tSTR,		pAny,		"tSTR",			"\"hello world\"",
"internal representation of text literals." ),

// string constant: dc.b csz, dc.w chars, dc.s text follows
TOKEN(tSTR2,	pAny,		"tSTR2",		"\"hello world\"",
"internal representation of text literals." ),

// identifier: dc.b csz, dc.b chars, dc.s text follows
TOKEN(tIDF,		pAny,		"tIDF",			"foo",
"internal representation of user defined names." ),


// ----	separators, brackets, flags ---------------------------------------
TOKEN(tKOMMA,	pAny,		",",		",",
"Separates arguments in argument list for instructions or procedures.\n"
"Separates indexes in item selector of multi-dimensional lists.\n"
"e.g.:  put \"a=\",a;  a=max(b,c); n=mylist[i,j]." ),

TOKEN(tRKauf,	pPostfix,	"(",		"(n[,…])",
"Round brackets override operator priority in expressions\n"
"or enclose argument list for procedures.\n"
"e.g.: put sin(pi/3); put 2*(3+4);" ),

TOKEN(tRKzu,	pAny,		")",		"(n[,…])",
"Round brackets override operator priority in expressions\n"
"or enclose argument list for procedures.\n"
"e.g.: put sin(pi/3); put 2*(3+4);" ),

TOKEN(tEKauf,	pPostfix,	"[",		"t|l[[n][to][n][,…]]",
"Square brackets enclose subrange or item selector for texts or lists.\n"
"e.g.: put \"abcde\"[2 to 3]; put {1,2,3}[1]." ),

TOKEN(tEKzu,	pAny,		"]",		"t|l[[n][to][n][,…]]",
"Square brackets enclose subrange or item selector for texts or lists.\n"
"e.g.: put \"abcde\"[2 to 3]; put {1,2,3}[1]." ),

TOKEN(tGKauf,	pAny,		"{",		"{…}",
"Curly brackets enclose list literals, procedure bodies,\n"
"or blocks of instructions with private variable scope.\n"
"items in lists may be named using the '=' operator\n"
"which also means, that you cannot use the '=' operator here\n"
"e.g.: var a,y; a = { 1, y=2, 3 }; put \"a=\",a,\" y=\",y\n"
"      proc foo() { put \"hello!\",nl }; foo()\n"
"      { var foo=0 }; put exists foo  // no" ),

TOKEN(tGKzu,	pAny,		"}",		"{…}",
"Curly brackets enclose list literals, procedure bodies,\n"
"or blocks of instructions with private variable scope.\n"
"items in lists may be named using the '=' operator\n"
"which also means, that you cannot use the '=' operator here\n"
"e.g.: var a,y; a = { 1, y=2, 3 }; put \"a=\",a,\" y=\",y\n"
"      proc foo() { put \"hello!\",nl }; foo()\n"
"      { var foo=0 }; put exists foo  // no" ),

TOKEN(tEOF,		pInstr,		"tEOF",			"(end of file)",
"Internally used to represent the end of a script file." ),


// ----	monadic operators -----------------------------------------

TOKEN(tPLPL,	pPostfix,	"++",		"n=[++v|v++]",
"pre- or post-increment numeric variable.\n"
"e.g.: var i=0; do while i<10; put i++; loop." ),

TOKEN(tMIMI,	pPostfix,	"--",		"n=[--v|v--]",
"pre- or post-decrement numeric variable.\n"
"e.g.: var i=10; do while i>0; put --i; loop." ),

TOKEN(tNOT,		pAny1Arg,		"!",		"n=!n",
"logical negation.\n"
"e.g.: if (!exists a) put \"a missing\",nl then." ),

TOKEN(tTILDE,	pAny1Arg,		"~",		"n=~n",
"bitwise negation.\n"
"e.g.: a = a & ~$20." ),

TOKEN(tAT,		pAny1Arg,		"@",		"i=@t",
"create identifier from text expression.\n"
"e.g.: var t=\"a\"; var a=1; put @t;" ),


// ----	diadic operators - assignments -----------------------------------------

TOKEN(tGL,		pAssign,		"=",		"v=x",
"assign value to variable.\n"
"assignment operators are 'right-oriented', that means: if multiple assignments\n"
"are made in an expression, they are evaluated right-to-left.\n"
"e.g.: var a = 47; var x,y,z; x=y=z=47;" ),

TOKEN(tPLGL,	pAssign,		"+=",		"v+=n",
"add value to variable.\n"
"assignment operators are 'right-oriented', that means: if multiple assignments\n"
"are made in an expression, they are evaluated right-to-left.\n"
"e.g.: var a=20; a += 33;" ),

TOKEN(tMIGL,	pAssign,		"-=",		"v-=n",
"subtract value from variable.\n"
"assignment operators are 'right-oriented', that means: if multiple assignments\n"
"are made in an expression, they are evaluated right-to-left.\n"
"e.g.: var a=33; a -= 20;" ),

TOKEN(tMUGL,	pAssign,		"*=",		"v*=n",
"multiply variable with value.\n"
"assignment operators are 'right-oriented', that means: if multiple assignments\n"
"are made in an expression, they are evaluated right-to-left.\n"
"e.g.: var a=5; a *= 4;" ),

TOKEN(tDVGL,	pAssign,		"/=",		"v/=n",
"divide variable by value.\n"
"assignment operators are 'right-oriented', that means: if multiple assignments\n"
"are made in an expression, they are evaluated right-to-left.\n"
"e.g.: var a=20; a /= 5;" ),

TOKEN(tMODGL,	pAssign,		"%=",		"v%=n",
"divide variable by value and store remainder.\n"
"assignment operators are 'right-oriented', that means: if multiple assignments\n"
"are made in an expression, they are evaluated right-to-left.\n"
"e.g.: var a=20; a %= 6;" ),

TOKEN(tHASHGL,	pAssign,		"#=",		"v#=t",
"append text to text variable.\n"
"assignment operators are 'right-oriented', that means: if multiple assignments\n"
"are made in an expression, they are evaluated right-to-left.\n"
"e.g.: var a=\"abc\"; a #= \"de\"; put a;" ),


TOKEN(tGTGTGL,	pAssign,		">>=",		"v>>=n",
"shift value of numeric variable bitwise right." ),


TOKEN(tLTLTGL,	pAssign,		"<<=",		"v<<=n",
"shift value of numeric variable bitwise left." ),


TOKEN(tANDANDGL, pAssign,		"&&=",		"v&&=n",
"calculate result of boolean AND and store result in left-side variable.\n"
"pruning not yet implemented." ),


TOKEN(tORORGL,	pAssign,		"||=",		"v||=n",
"calculate result of boolean OR and store result in left-side variable.\n"
"pruning not yet implemented." ),


TOKEN(tXORGL,	pAssign,		"^=",		"v^=n",
"calculate result of bitwise exclusive OR and store result in left-side variable." ),


TOKEN(tANDGL,	pAssign,		"&=",		"v&=n",
"calculate result of bitwise AND and store result in left-side variable." ),


TOKEN(tORGL,	pAssign,		"|=",		"v|=n",
"calculate result of bitwise OR and store result in left-side variable." ),


TOKEN(tHASHHASHGL, pAssign,		"##=",		"v##=l",
"append item to list, list to item, or list to list.\n"
"assignment operators are 'right-oriented', that means: if multiple assignments\n"
"are made in an expression, they are evaluated right-to-left.\n"
"e.g.: var a=1; a #= { 2,3,4,5 }; a#=6; put a;" ),



// ----	diadic operators ------------------------------------------

TOKEN(tADD,		pAdd,		"+",		"[n|l]=[n|t|l]+[n|t|l]",
"(1) operator: add two numerical values.\n"
"    add two numerical values or text values, which are converted to numbers,\n"
"    results in a number. if one operand is a list, the result is a list, \n"
"    where the operation was applied to all items. if both are lists, they \n"
"    should match in size and the operation is applied to all matching items.\n"
"    e.g.: 4+5 = 9;  ({4,5}+3) = {7,8};  ({2,3})+{4,5} = {6,8}.\n"
"    operator priority is below multiplication.\n"
"    text+text may some day result in text for high precision calculations.\n"
"(2) optional number sign for positive number.\n"
"    note: preceding a text with operator + converts it to a number.\n"
"    e.g. put +123, +$affe, +\"0123\", +\"$affe\";" ),

TOKEN(tSUB,		pAdd,		"-",		"[n|l]=[n|t|l]-[n|t|l]",
"(1) operator: subtract two numerical values.\n"
"    subtract two numerical values or text values, which are converted to numbers,\n"
"    results in a number. if one operand is a list, the result is a list, \n"
"    where the operation was applied to all items. if both are lists, they \n"
"    should match in size and the operation is applied to all matching items.\n"
"    e.g.: 9-5 = 4;  ({4,5})-3 = {1,2};  ({4,5})-{2,3} = {2,2}.\n"
"    operator priority is below multiplication.\n"
"    text-text may some day result in text for high precision calculations.\n"
"(2) number sign for negative number.\n"
"    note: preceding a text with operator - converts it to a number.\n"
"    e.g. put -123, -$affe, -\"0123\", -\"$affe\";" ),

TOKEN(tMUL,		pMul,		"*",		"[n|l]=[n|t|l]*[n|t|l]",
"(1) operator: multiply two numerical values.\n"
"    multiply two numerical values or text values, which are converted to numbers,\n"
"    results in a number. if one operand is a list, the result is a list, \n"
"    where the operation was applied to all items. if both are lists, they \n"
"    should match in size and the operation is applied to all matching items.\n"
"    e.g.: 4*5 = 20;  ({4,5})*3 = {12,15};  ({4,5})*{2,3} = {8,15}.\n"
"    operator priority is above addition.\n"
"    text*text may some day result in text for high precision calculations.\n"
"(2) wildcard in path pattern for dir().\n"
"    e.g. var cafélogo = dir(\"./*.gif\");.\n"
"(3) flag for del statement to delete all variables in local scope.\n"
"    e.g.: del *.\n"
"(4) flag in procedure parameter list to accept any number of arguments.\n"
"    e.g.: proc zähle(a,*){ put \"a=\",a,\" argc=\",count locals,nl };" ),
	
TOKEN(tDIV,		pMul,		"/",		"[n|l]=[n|t|l]/[n|t|l]",
"    operator: divide one numerical value by another.\n"
"    divide two numerical values or text values, which are converted to numbers,\n"
"    results in a number. if one operand is a list, the result is a list, \n"
"    where the operation was applied to all items. if both are lists, they \n"
"    should match in size and the operation is applied to all matching items.\n"
"    e.g.: 20/5 = 4;  ({40,50})/5 = {8,10};  ({40,50})/{8,5} = {5,10}.\n"
"    operator priority is above addition.\n"
"    text/text may some day result in text for high precision calculations." ),

TOKEN(tMOD,		pMul,		"%",		"[n|l]=[n|t|l]%[n|t|l]",
"(1) operator: remainder of division of two numerical values.\n"
"    divide two numerical values or text values, which are converted to numbers,\n"
"    results in a number. if one operand is a list, the result is a list, \n"
"    where the operation was applied to all items. if both are lists, they \n"
"    must match in size and the operation is applied to all matching items.\n"
"    e.g.: 21.5%2.5 = 1.5;  ({33,21})%5 = {3,1};  ({36,27}/{5,10}) = {1,7}.\n"
"    operator priority is above addition.\n"
"    note: text%text may some day result in text for high precision calculations.\n"
"(2) flag for binary number literal.\n"
"    e.g.: -%0101.1 = -5.5." ),

TOKEN(tHASH,	pHash,		"#",		"[put,get,…]#n,x[,…]\n\tt=t#t",
"(1) Select stream for i/o instruction:\n"
"    open, openin, openout, close, put, get, read, write, ioctl,\n"
"    info, variables, words, pwd, dir and others.\n"
"    e.g.: open #4, \"hello.txt\"; put#4,\"hello world\",nl; close#4;\n"
"(2) operator: concatenate two strings. result is a string.\n"
"    if either operand is not text, it is converted to text first.\n"
"    \"ant\"#\"0123.40\"  =  \"ant0123.40\"\n"
"    \"anton\"#0123.40  =  \"anton123.4\"\n"
"    123.456#0123.40  =  \"123.456123.4\"\n"
"    operator priority is between add/sub and comparisions:\n"
"    e.g.: a#b+c  =  a#(b+c)\n"
"          a#b>c  =  (a#b)>c."),

TOKEN(tHASHHASH, pHash,		"##",		"l=l##l",
"operator: concatenate two lists. the result is a list.\n"
"if either operand is not a list, it is converted to a list first.\n"
"{1,2,3}##{4,5,6}  =  {1,2,3,4,5,6}\n"
"1##{2}##\"anton\"   =  {1,2,\"anton\"}\n"
"{1,2,3}##\"anton\"  =  {1,2,3,\"anton\"}\n"
"\"anton\"##{1,2,3}  =  {\"anton\",1,2,3}\n"
"operator priority is between add/sub and comparisions:\n"
"e.g.: a##b+c  =  a##(b+c)\n"
"      a##b>c  =  (a##b)>c."),

TOKEN(tGT,		pCmp,		">",		"n=x>x",
"operator: compare two values.\n"
"returns 1 if left operand is greater than right operand.\n"
"if values of different type are compared then error condition is set.\n"
"lists are compared by comparing all corresponding items. recursively.\n"
"e.g.: if (a>55) put \"a>55\" then; if(b>\"aaa\") put \"b>aaa\" then;" ),

TOKEN(tLT,		pCmp,		"<",		"n=x<x",
"operator: compare two values.\n"
"returns 1 if left operand is less than right operand.\n"
"if values of different type are compared then error condition is set.\n"
"lists are compared by comparing all corresponding items. recursively.\n"
"e.g.: if (a<55) put \"a<55\" then; if(b<\"aaa\") put \"b<aaa\" then;" ),

TOKEN(tGE,		pCmp,		">=",		"n=x>=x",
"operator: compare two values.\n"
"returns 1 if left operand is greater than or equal to right operand.\n"
"if values of different type are compared then error condition is set.\n"
"lists are compared by comparing all corresponding items. recursively.\n"
"e.g.: if (a>=55) put \"a≥55\" then; if(b>=\"aaa\") put \"b≥aaa\" then;" ),

TOKEN(tLE,		pCmp,		"<=",		"n=x<=x",
"operator: compare two values.\n"
"returns 1 if left operand is less than or equal to right operand.\n"
"if values of different type are compared then error condition is set.\n"
"lists are compared by comparing all corresponding items. recursively.\n"
"e.g.: if (a<=55) put \"a≤55\" then; if(b<=\"aaa\") put \"b≤aaa\" then;" ),

TOKEN(tEQ,		pCmp,		"==",		"n=x==x",
"operator: compare two values.\n"
"returns 1 if left and right operand have the same value.\n"
"values of different data type are considered not equal.\n"
"lists are compared by comparing all corresponding items. recursively.\n"
"e.g.: if (a==55) put \"a equals 55\" then; if(b==\"aaa\") put \"b == aaa\" then;" ),

TOKEN(tNE,		pCmp,		"!=",		"n=x!=x",
"operator: compare two values.\n"
"returns 1 if left and right operand have different values.\n"
"values of different data type are considered not equal.\n"
"lists are compared by comparing all corresponding items. recursively.\n"
"e.g.: if (a!=55) put \"a!=55\" then; if(b!=\"aaa\") put \"b!=aaa\" then;" ),

TOKEN(tLTLT,	pRot,			"<<",		"n=n<<n",
"operator: bitwise shift left, padding with 0.\n"
"e.g.: 8<<2     = 32\n"
"      0.75<<1  = 1.5\n"
"      2.125<<8 = 544" ),

TOKEN(tGTGT,	pRot,		">>",		"n=n>>n",
"operator: bitwise shift right, padding with 0.\n"
"e.g.: 32>>2  = 8\n"
"      544>>8 = 2.125\n"
"      1.5>>1 = 0.75" ),

TOKEN(tANDAND,	pBoo,		"&&",		"n=n&&n",
"operator: logical AND.\n"
"if number1 is false, then number2 is not evaluated (pruning)\n"
"e.g.: if (a==0&&a!=0) log \"this can not happen\" then." ),

TOKEN(tOROR,	pBoo,		"||",		"n=n||n",
"operator: logical OR.\n"
"if number1 is true, then number2 is not evaluated (pruning)\n"
"e.g.: if (a==0||a!=0) log \"this is always true\" then." ),

TOKEN(tAND,		pBit,		"&",		"n=n&n",
"operator: bitwise AND.\n"
"e.g.: $FE & $0F = $0E." ),

TOKEN(tOR,		pBit,		"|",		"n=n|n",
"operator: bitwise OR.\n"
"e.g.: $0E | $58 = $5E." ),

TOKEN(tXOR,		pBit,		"^",		"n=n^n",
"operator: bitwise XOR (exclusive or).\n"
"e.g.: $0E ^ $5E = $50."	),

TOKEN(tDOT,		pPostfix,	".",		"v=l.i",
"operator: select named item in list.\n"
"e.g.: var a={1,2,3}; var a.b=4; rename a[2]=\"z\"; log a.z,a.b;" ),


// ----	triadic operators -----------------------------------------

TOKEN(tQMARK,	pSel,		"?",		"x=n1?x2:x3",
"operator: select expression2 or 3 based on number1.\n"
"if number1 is false then expression2 is not evaluated\n"
"else expression3 is skipped. (pruning)\n"
"operator can be extended like: a = f1 ? n1 : f2 ? n2 : f3 ? n3 : n4\n"
"e.g.: return a>b ? a : b;"	),

TOKEN(tCOLON,	pSel,		":",		"n1?x2:x3",
"operator: select expression2 or 3 based on number1.\n"
"if number1 is false then expression2 is not evaluated\n"
"else expression3 is skipped. (pruning)\n"
"operator can be extended like: a = f1 ? n1 : f2 ? n2 : f3 ? n3 : n4\n"
"e.g.: return a>b ? a : b;"	),



// ==== now regular identifier-type words follow ==================


// ----	special words (sort of separator; flags) ------------------

TOKEN(tFROM, 	pAny,		"from",		"from",
"special separator for 'convert' statement." ),

TOKEN(tTO,		pAny,		"to",		"t|l[[n][to][n][,…]]",
"Special separator for 'convert' statement.\n"
"Subrange selector for texts or lists; e.g. my_list[a to e]" ),	


// ----	constants -------------------------------------------------

TOKEN(tEC,		pAny,		"ec",		"ec",
"Euler's constant: e = 2.718281828459045.\n"
"f'(x)=f(x)  <=>  f(x)=exp(e,x)." ),

TOKEN(tPI,		pAny,		"pi",		"pi",
"natural constant: π = 3.141592653589793.\n"
"circumference of circle = radians * π.\n"
"e.g.: put \"sin(180°)=\",sin(pi);" ),

TOKEN(tNEWLINE,	pAny,		"nl",		"nl",
"text constant for line break.\n"
"e.g.: put \"hello!\",nl;" ),

TOKEN(tTAB,		pAny,		"tab",		"tab",
"text constant for tabulator.\n"
"e.g.: put \"foo =\",tab,foo,nl;" ),

TOKEN(tSTDIN,	pAny,		"stdin",	"stdin",
"constant for the standard input stream: 0.\n"
"this is the default stream for 'get'.\n"
"printing to stdin on a tty colorizes the text as set in ~/.vipsi/*.prefs\n"
"e.g.: get foo  =  get #stdin,foo." ),

TOKEN(tSTDOUT,	pAny,		"stdout",	"stdout",
"constant for the standard output stream: 1.\n"
"this is the default stream for 'put'.\n"
"printing to stdout on a tty colorizes the text as set in ~/.vipsi/*.prefs\n"
"e.g.: put foo  =  put #stdout,foo." ),

TOKEN(tSTDERR,	pAny,		"stderr",	"stderr",
"constant for the standard error stream: 2.\n"
"this is the default stream for 'log'.\n"
"printing to stderr on a tty colorizes the text as set in ~/.vipsi/*.prefs\n"
"e.g.: log foo  =  put #stderr,foo."	),


// ----	functions -------------------------------------------------

TOKEN(tFILE,	pAny1Arg,		"file",		"t=file t | file t=t | file t#=t",
"1) read file in binary mode. yields a text value.\n"
"2) save text in binary mode to file.\n"
"3) append text in binary mode to file."				),

TOKEN(tMDATE,	pAny1Arg,		"mdate",	"n=mdate t",
"get modification date of file. yields a numeric value."	),

TOKEN(tCOUNT,	pAny1Arg,		"count",	"count s|l",
"querry number of elements in text or list"				),

TOKEN(tINDEX,	pAny1Arg,		"index",	"index x",
"get position of item in list" ),

TOKEN(tGETNAME,	pAny1Arg,		"name",		"name v",
"querry name of variable. e.g.: name a[0]"				),

TOKEN(tRANDOM,	pAny1Arg,		"random",	"random n",
"get a random number in range [0…[n (float!)"			),

TOKEN(tABS,		pAny1Arg,		"abs",		"abs n",
"unsigned, absolute value of numeric value"				),

TOKEN(tSIGN,	pAny1Arg,		"sign",		"sign n",
"sign of numeric value"									),

TOKEN(tINT,		pAny1Arg,		"int",		"int n",
"integral part of numeric value"						),

TOKEN(tFRACT,	pAny1Arg,		"fract",	"fract n",
"fractional part of numeric value"						),

TOKEN(tROUND,	pAny1Arg,		"round",	"round n",
"round to nearest. xx.5 rounds upwards."				),

TOKEN(tMIN,		pAnyNArg,		"min",		"v=min(n[,…]) | v=min(l)",
"minimum of values. result can be a variable reference. if a list is passed\n"
"as single argument, then a reference to the smallest item is returned.\n"
"error is set if different data types are compared.\n"
"if two values are equal, the first is returned.\n"
"e.g.: a=min(a,99); put min({1,6,3,4}); min(a,b)=0; put name(min(a,b));"),

TOKEN(tMAX,		pAnyNArg,		"max",		"v=max(n[,…]) | v=max(l)",
"maximum of values. result can be a variable reference. if a list is passed\n"
"as single argument, then a reference to the largest item is returned.\n"
"error is set if different data types are compared.\n"
"if two values are equal, the first is returned.\n"
"e.g.: a=max(a,99); put max({1,6,3,4}); max(a,b)=0; put name(max(a,b));"),

TOKEN(tCOS,		pAny1Arg,		"cos",		"n=cos n",
"cosinus of angle.\n"
"full circle = 2*pi." ),

TOKEN(tSIN,		pAny1Arg,		"sin",		"n=sin n",
"sinus of angle.\n"
"full circle = 2*pi." ),

TOKEN(tTAN,		pAny1Arg,		"tan",		"n=tan n",
"tangens of angle.\n"
"full circle = 2*pi." ),

TOKEN(tACOS,	pAny1Arg,		"acos",		"n=acos n",
"angle from cosinus.\n"
"result range: 0 … +pi." ),

TOKEN(tASIN,	pAny1Arg,		"asin",		"n=asin n",
"angle from sinus.\n"
"result range: -pi/2 … +pi/2." ),

TOKEN(tATAN,	pAny1Arg,		"atan",		"n=atan n",
"angle from tangens.\n"
"result range: -pi/2 … +pi/2." ),

TOKEN(tCOSH,	pAny1Arg,		"cosh",		"n=cosh n",
"cosinus hyperbolicus." ),

TOKEN(tSINH,	pAny1Arg,		"sinh",		"n=sinh n",
"sinus hyperbolicus." ),

TOKEN(tTANH,	pAny1Arg,		"tanh",		"n=tanh n",
"tangens hyperbolicus." ),

TOKEN(tLOGN,	pAny,		"logn",		"n=logn(n1,n2)",
"logarithm of number 2 to base number 1.\n"
"e.g.: logn(16,256) = 2." ),

TOKEN(tLOG2,	pAny1Arg,		"log2",		"n=log2 n",
"logarithm of number to base 2.\n"
"e.g.: log2(4) = 2." ),

TOKEN(tLOGE,	pAny1Arg,		"loge",		"n=loge n",
"logarithm of number to base e.\n"
"e.g.: loge(e*e) = 2." ),

TOKEN(tLOG10,	pAny1Arg,		"log10",	"n=log10 n",
"logarithm of number to base 10.\n"
"e.g.: log10(100) = 2." ),

TOKEN(tEXPN,	pAny,		"exp",		"n=exp(n1,n2)",
"number 1 raised to the power of number 2.\n"
"e.g. exp(16,2) = 256." ),

TOKEN(tEXP2,	pAny1Arg,		"exp2",		"n=exp2 n",
"2 raised to the power of number.\n"
"e.g. exp2(3) = 8." ),

TOKEN(tEXPE,	pAny1Arg,		"expe",		"n=expe n",
"e raised to the power of number.\n"
"e.g.: expe(2) = e*e." ),

TOKEN(tEXP10,	pAny1Arg,		"exp10",	"n=exp10 n",
"10 raised to the power of number.\n"
"e.g.: exp10(2) = 100." ),

TOKEN(tSQUARE,	pAny1Arg,		"square",	"n=square n",
"number * number.\n"
"e.g.: square 5 = 25." ),

TOKEN(tSQRT,	pAny1Arg,		"sqrt",		"n=sqrt n",
"square root of number.\n"
"e.g.: sqrt 25 = 5." ),

TOKEN(tISTEXT,	pAny1Arg,		"istext",	"n=istext x",
"test whether expression is a text value.\n"
"e.g.: istext(\"foo\") = 1; istext({}) = 0." ),

TOKEN(tISNUMBER,pAny1Arg,		"isnumber",	"n=isnumber x",
"test whether expression is a numeric value.\n"
"e.g.: isnumber(1+2) = 1; isnumber({}) = 0." ),

TOKEN(tISLIST,	pAny1Arg,		"islist",	"n=islist x",
"test whether expression is a list.\n"
"e.g.: islist({1,2}) = 1; islist(12) = 0." ),

TOKEN(tISPROC,	pAny1Arg,		"isproc",	"n=isproc x",
"test whether expression is a user-defined procedure.\n"
"e.g.: proc foo(){}; isproc(foo) = 1; isproc(\"foo\") = 0." ),

TOKEN(tISFILE,	pAny1Arg,		"isfile",	"n=isfile t",
"test whether path refers to a file.\n"
"e.g.: var a = isfile(\"~/bin/vipsi\");" ),

TOKEN(tISDIR,	pAny1Arg,		"isdir",	"n=isdir t",
"test whether path refers to a directory.\n"
"e.g.: isdir(\"/\") = 1; isdir(\"\") = 0." ),

TOKEN(tEXISTS,	pAny1Arg,		"exists",	"n=exists v",
"test whether variable exists.\n"
"e.g.: var a={1,2,3}; exists a[3] = 1; exists a[5] = 0." ),

TOKEN(tTOTEXT,	pAny1Arg,		"string",	"t=string x",
"convert expression to text representation. \n"
"e.g.: string(47+11) = \"58\"." ),

TOKEN(tTOUPPER,	pAny1Arg,		"upperstr",	"t=upperstr t",
"convert text to all uppercase characters conforming to utf-8 unicode.\n"
"e.g. \"HELLO WORLD!\" = upperstr(\"Hello World!\")." ),

TOKEN(tTOLOWER,	pAny1Arg,		"lowerstr",	"t=lowerstr t",
"convert text to all lowercase characters conforming to utf-8 unicode.\n"
"e.g. \"hello world!\" = lowerstr(\"Hello World!\")." ),

TOKEN(tCHARSTR,	pAny1Arg,		"charstr",	"t=charstr n",
"convert ucs-4 character (number) to utf-8 character (text).\n"
"e.g.: charstr 97 = \"a\"." ),

TOKEN(tCHAR, 	pAny1Arg,		"charcode",	"n=charcode t",
"convert first utf-8 character in text to ucs-4 character number.\n"
"e.g.: charcode \"a\" = 97." ),

TOKEN(tHEXSTR, 	pAnyNArg,		"hexstr",	"t=hexstr(n1[,n2])",
"convert number 1 to hexadecimal digit string.\n"
"resulting text is sized to fit or\n"
"sized according to number 2, truncating or padding 0's to the left.\n"
"e.g.: hexstr(240) = \"F0\"; hexstr(240,4) = \"00F0\"; hexstr(240,1) = \"0\"." ),

TOKEN(tBINSTR, 	pAnyNArg,		"binstr",	"t=binstr(n1[,n2])",
"convert number 1 to binary digit string.\n"
"resulting text is sized to fit or \n"
"sized according to number 2, truncating or padding 0's to the left.\n"
"e.g.: binstr(10,8) = \"00001010\"; binstr(10,2) = \"10\"." ),

TOKEN(tSUBSTR,	pAnyNArg,		"substr",	"t=substr(t,n1,n2)",
"substring [number1 to number2] from text\n"
"-> number2-number1+1 characters.\n"
"e.g.: substr(\"123456\",3,4) = \"34\"" ),

TOKEN(tMIDSTR,	pAnyNArg,		"midstr",	"t=midstr(t,n1[,n2])",
"get substring [number1 to number1+number2-1] from text\n"
"-> number2 characters.)\n"
"if number2 is omitted, then get substring up to end of text.\n"
"e.g.: midstr(\"123456\",3,2) = \"34\"" ),

TOKEN(tLEFTSTR,	pAnyNArg,		"leftstr",	"t=leftstr(t,n)",
"substring: get number bytes from the left side of the text.\n"
"same as text[to number]." ),

TOKEN(tRIGHTSTR,pAnyNArg,		"rightstr",	"t=rightstr(t,n)",
"substring: get number bytes from the right side of the text.\n"
"e.g.: rightstr(\"anton\",3) = \"ton\"." ),

TOKEN(tDATESTR,	pAny1Arg,		"datestr",	"t=datestr n",
"convert numeric date format to readable text.\n"
"e.g.: datestr 0 = 1970-01-01 01:00:00." ),

TOKEN(tNOW, 	pAny,		"now", "n=now",
"get system time.\n"
"returns local time in seconds incl. a fractional part.\n"
"time base may vary!\n"
"e.g. log\"current date and time = \",datestr(now),nl;\n"
"     var a=0,t0=now; do while ++a<100000; loop; put \"time=\",now-t0;"),

TOKEN(tDATEVAL,	pAny1Arg,		"dateval",	"n=dateval t",
"convert readable date text to numeric format.\n"
"e.g.: dateval \"2002-04-01 12:00\" = 1017658800.\n"
"	  dateval \"2002.04\"          = 1017529200." ),

TOKEN(tFIND,	pAnyNArg,		"find",		"n=find(t1,t2[,t3])",
"find first occurance of text 2 in text 1.\n"
"optionally starting search at index t3\n"
"returns index of position found or 0.\n"
"e.g.: find(\"hello world\",\"l\") = 3." ),

TOKEN(tRFIND,	pAnyNArg,		"rfind",	"n=rfind(t1,t2[,t3])",
"find last occurance of text 2 in text 1.\n"
"optionally starting search at index t3\n"
"returns index of position found or 0.\n"
"e.g.: rfind(\"hello world\",\"l\") = 10." ),

TOKEN(tENV, 	pAny,		"env", "l=env",
"create environment variables list.\n"
"returns a list with one item for each environment variable.\n"
"each item is a text containing the variable's value.\n"
"each item is named with the environment variable's name.\n"
"e.g.: var e=env,i=0; do while ++i<=count e log name e[i],\"=\",e[i],nl loop;" ),

TOKEN(tMATCH,	pAnyNArg,		"match",	"n=match(t1,t2[,n])",
"test whether text 1 matches pattern in text 2.\n"
"returns boolean value: 0 (no) or 1 (yes).\n"
"the optional flag consists of 3 bits:\n"
"    1 = enable backslash escaping\n"
"    2 = slash must match slash (e.g. file paths)\n"
"    4 = dot must match dot (e.g. file names)" ),

TOKEN(tFULLPATH,pAny1Arg,		"fullpath",	"t=fullpath t",
"get fully qualified path for partial path.\n"
"expands \"./\" and \"../\", symbolic links, \"~\" and relative path\n"
"to the absolute file or directory path." ),


// ----	instructions ------------------------------------------------------

TOKEN(tNEW,		pInstr,		"new",		"new [i[=x]|file t|dir t][,…]",
"create variable, file or directory.\n"
"opt. assign value to variable." ),

TOKEN(tDEL,		pInstr,		"del",		"del [i|file t|dir t][,…]",
"delete and forget variable, file or directory.\n"
"e.g.: del a,b[1],a.wert" ),

TOKEN(tSWAP,	pInstr,		"swap",		"swap [v,v|file t,file t][,…]",
"swap two variables including their names.\n"
"meant to reorder items in lists,\n"
"not to exchange the values of two variables."
"e.g.: var z.a=100,z.b=200; swap z[1],z[2]; put z;" ),

TOKEN(tVAR,		pInstr,		"var",		"var i[=x][,…]",
"Create variable if it does not already exist.\n"
"optionally assign initial value" ),

TOKEN(tFREEZE,	pInstr,		"freeze",	"freeze [file] t",
"compress text or file. undo compression with melt.\n"
"note: files must fit into ram twice.\n"
"e.g.: var a=\"fuzzy\";a#=a;a#=a;a#=a; freeze a; count a;" ),

TOKEN(tMELT,	pInstr,		"melt",		"melt [file] t",
"uncompress text or file which has been compressed with freeze.\n"
"note: files must fit into ram twice.\n"
"e.g.: var a=\"fuzzy\";a#=a;a#=a;a#=a; freeze a; melt a;" ),

							
TOKEN(tPUT,		pInstr,		"put",		"put[#n,]x[,…]",
"write data in text format.\n"
"default stream is stdout.\n"
"default text encoding is UTF-8 unicode.\n"
"printing to stdout on a tty colorizes the text as set in ~/.vipsi/*.prefs\n"
"isText:   'as is', character set and end-of-line conversion applied.\n"
"isNumber: numbers are written in readable format; e.g. +123.456e-78.\n"
"isList:   enclosed in curly brackets; e.g.: { 123, \"anton\", {} }.\n"
"isProc:   prints source (if available) or disassembly." ),

TOKEN(tLOG,		pInstr,		"log",		"log x[,…]",
"write data to stderr.\n"
"printing to stderr on a tty colorizes the text as set in ~/.vipsi/*.prefs\n"
"except for that, 'log' works exactly like 'put'." ),

TOKEN(tGET,		pInstr,		"get",		"get[#n,]v[,…]",
"read data in text format.\n"
"default stream is stdin.\n"
"default text encoding is UTF-8 unicode.\n"
"default timeout is off (blocking).\n"
"input stops at next end of line for each variable.\n"
"reading from a tty (terminal) uses the line editor.\n"
"printing to stdin on a tty colorizes the text as set in ~/.vipsi/*.prefs\n"
"data interpretation depends on destination variable type:\n"
"isText:   character set conversion applied.\n"
"isNumber: numeric format: -123.456e+78\n"
"others:   error." ),


TOKEN(tEDIT,	pInstr,		"edit",		"edit[#n,]v[,…]",
"edit (write and reread) data in text format.\n"
"default stream is stdin.\n"
"default text encoding is UTF-8 unicode.\n"
"default timeout is off (blocking).\n"
"edit finished with end of line (return) for each variable.\n"
"reading from a tty (terminal) uses the line editor.\n"
"data presentation is the same as for 'put'." ),

TOKEN(tGETCHAR,	pInstr,		"getchar",		"getchar[#n,]v[,…]",
"read single character in text format.\n"
"default stream is stdin. \n"
"returns only complete unicode characters.\n"
"default text encoding is UTF-8 unicode.\n"
"default timeout is off (blocking).\n"
"reads from tty (terminal) without echo.\n"
"data deposition depends on destination variable type:\n"
"isText:   character is stored in UTF-8 format.\n"
"isNumber: character is stored in UCS-4 format.\n"
"others:   error." ),

TOKEN(tWRITE,	pInstr,		"write",	"write[#n,]v",
"write text in binary mode.\n"
"default stream is stdout.\n"
"no conversions applied. text is written 'as is'." ),

TOKEN(tREAD,	pInstr,		"read",		"read[#n,]v",
"read text in binary mode.\n"
"default stream is stdin.\n"
"default timeout is off (blocking).\n"
"reads from tty (terminal) without echo.\n"
"no conversion applied. text is read 'as is'.\n"
"destination text variable is filled with data from stream.\n"
"on timeout, eof or error the text is truncated." ),

TOKEN(tIOCTL,	pInstr,		"ioctl",	"ioctl[#n,] [i=x|v=i]",
"Set stream settings or querry stream state\n"
"•••under development•••\n"
"set only:\n"
"    ioctl flush|flushin|flushout\n"
"set/read:\n"
"    ioctl timeout = 0 (off)  or  number (seconds)\n"
"    ioctl text    = \"utf-8\"  or  \"mac-roman\"\n"
"    ioctl pos     = number         (file: read-write-pointer)\n"
"                    {row,col}      (tty:  cursor location)\n"
"read only:\n"
"    ioctl var = type               (\"tty\", \"file\", etc.)\n"
"    ioctl var = inavail            (bytes readable w/o blocking)\n"
"    ioctl var = outfree            (bytes writable w/o blocking)\n"
"    ioctl var = error              (0=ok, 1=eof, 2=timeout, ...)\n"
"    ioctl var = size               (file: number, tty: {rows,cols})\n"
"    ioctl var = name               (filename)\n"
"    ioctl var = isopen/isopenin/isopenout" ),

TOKEN(tEVAL,	pAny1Arg,		"eval",		"eval t  |  x=eval t",
"evaluate text as expression, e.g. a = eval(\"2*3\")\n"
"the text is parsed just like a script, so almost every expression\n"
"is possible here, including execution of own procedures.\n"
"also, the text can access all variables from the current context." ),

TOKEN(tCALL,	pAnyNArg,		"call",		"call t1[,…]  |  x=call(t1[,…])",
"call another vipsi script like a function with parameters and return a result.\n"
"the called script text1 is very similar to a standard shell script\n"
"except that it can be passed and return variables of any type.\n"
"it shares the preferences of the current context\n"
"but cannot access it's variables and functions.\n"
"e.g.: var u_rec = call(\"utils/fetch_db_entry.vs\",user_id,number)" ),

TOKEN(tSYS,		pAnyNArg,		"sys",		"sys [#n,]t1[,…]  |  t=sys(t1[,…])",
"execute a system command or script with parameters and return it's text output.\n"
"the command text1 is executed and passed all the supplied text parameters.\n"
"(1) instruction: print output to stdout or selected stream number.\n"
"(2) function:    all it's output to stdout is returned as a single text value." ),

TOKEN(tINCLUDE,	pAny1Arg,		"include",	"include t[,…]  |  x=include t",
"load and execute named script file.\n"
"the script is executed in the current context.\n"
"this means it behaves just as if pasted verbatim at the current position.\n"
"all variables and procedures defined in this script still exist after it's end.\n"
"'end' or 'return' exit from the script only, not from the current context.\n"
"also, the script may return a result or error code with 'return'." ),

TOKEN(tDIR,		pAny1Arg,		"dir",		"l=dir t  |  dir[#n,]t",
"get contents of named directory.\n"
"name may be full or partial or start with ~ for user's home directory\n"
"and may contain a match pattern with wildcards for files to list.\n"
"(1) function:    returns a 2-dimensional list.\n"
"(2) instruction: print folderlisting to stdout or stream number." ),

TOKEN(tWAIT,	pInstr,		"wait",		"wait n",
"wait number seconds.\n"
"e.g.: wait 0.33" ),

TOKEN(tINFO,	pInstr,		"info",		"info[#n,]i[,…]",
"print info for identifier: info idf | token | @\"idf|token\" | \"token|idf\""	),

TOKEN(tSORT,	pInstr,		"sort",		"sort l[,…]",
"sort list in ascending order"													),

TOKEN(tRSORT,	pInstr,		"rsort",	"rsort l[,…]",
"sort list in descending order"													),

TOKEN(tSPLIT,	pAnyNArg,		"split",	"split v1[,t2]  |  l=split(t1[,t2])",
"split text1 at any occurance of text2. yields a list of texts.\n"
"1) instruction: the contents of variable1 is replaced by the result list\n"
"2) function: the result is returned and argument text1 is not modified\n"
"the separator text2 is removed, not preserved.\n"
"if text2 is omitted then text1 is split at char 0, 10, 13 and 10+13\n"
"if text2 is a numeric argument then it is taken as a character code\n"
"if text1 ends with text2 then a final empty text is appended to the list.\n"
"if text1 is a list of texts then the result is a list of lists of texts.\n"
"e.g.: var mytext  = file \"myfile\"; split mytext;\n"
"      var mydbase = split(mytext,\"\\t\")"										),

TOKEN(tCONVERT,	pAnyNArg,		"convert",	"convert v from|to i  |  t=convert(t from|to i)",
"convert text from utf-8 to named encoding or vice versa.\n"
"(1) instruction: if used as an instruction, the supplied variable is converted.\n"
"(2) function: if used as a function, the converted data is returned as result.\n"
"possible encoding:\n"
"    printable      escape characters breaking vipsi's syntax for text literals\n"
"    quoted         escape and add '\"'s at both ends\n"
"    html           convert > to &gt; etc.; does not convert non_ascii characters\n"
"    mac_roman      convert to mac roman character set\n"
"    iso_latin_1    convert to iso latin 1 character set\n"
"    iso_latin_2    convert to iso latin 2 character set\n"
"    windows        convert to iso latin 1\n"
"    archimedes     convert to iso latin 1\n"
"    ucs_2          convert to 2-byte unicode\n"
"    ucs_4          convert to 4-byte unicode\n"
"    ascii_us       convert to 7-bit ascii\n"
"    ascii_ger      convert to 7-bit ascii, german variant (Ä…ß instead of […\\)\n"
"    dos            convert to dos latin US character set (codepage 437)\n"
"    atari          convert to atari st character set\n"
"e.g.: convert mytext to printable;\n"
"      convert mytext to mac_roman;\n"
"      convert mytext from html;\n"
"      log convert(mytext to quoted);"),

TOKEN(tOPEN,	pInstr,		"open",		"open[#n,]filename",
"open file/stream for reading and writing"										),

TOKEN(tOPENIN,	pInstr,		"openin",	"openin[#n,]filename",
"open file/stream for reading"													),

TOKEN(tOPENOUT,	pInstr,		"openout",	"openout[#n,]filename",
"open file/stream for writing, clearing file"									),

TOKEN(tCLOSE,	pInstr,		"close",	"close[#n]",
"close open file/stream"														),

TOKEN(tSETNAME,	pInstr,		"rename",	"rename v=t  |  rename file t=t",
"assign name to variable. e.g. rename a[0]=\"anton\""							),


// ----	not tKOMMA-repeatable instructions ---------------------------------

TOKEN(tSEMIK,	pInstr,		";",		";",
"instruction which does nothing.\n"
"may be used to separate statements if you like.\n"
"e.g.: var a=0; log a; a++; log a;" ),

TOKEN(tCD,		pInstr,		"cd",		"cd t",
"change working directory.\n"
"e.g.: cd \"../\";" ),

TOKEN(tPWD,		pInstr,		"pwd",		"pwd[#n]",
"print working directory path.\n"
"default stream is stdout.\n"
"similar to log fullpath \"./\"." ),

TOKEN(tWORDS,	pInstr,		"words",	"words[#n]",
"List most known tokens, procedures and functions.\n"
"default stream is stdout." ),

TOKEN(tGLOBALS, pAny,		"globals","globals[#n]  |  v=globals",
"1) instruction: List all defined variables.\n"
"   default stream is stdout.\n"
"2) plain vanilla access to the variable 'globals',\n"
"   the mother of all data in vipsi. yields a list." ),

TOKEN(tPROC,	pInstr,		"proc",		"proc i (…) { … }",
"define a procedure/function/sub routine.\n"
"e.g.: proc fak(n) { if (n>1) return n*fak(n-1); then; return 1; };\n"
"      log \"fak(5) = \",fak(5),nl;" ),

TOKEN(tRETURN,	pInstr,		"return",	"return x",
"end function or script and return result value.\n"
"e.g.: proc geomed(a,b) { return sqrt(a*b); }" ),

TOKEN(tEND,		pInstr,		"end",		"end",
"end of script or end of procedure returning no value." ),

TOKEN(tDO,		pInstr,		"do",		"do … loop",
"repeat statements between do and loop.\n"
"e.g.: var i=1; do; put i; while i<10; i++; loop;" ),

TOKEN(tTHEN,	pInstr,		"then",		"if n … [else …] then",
"execute statements only if value is true.\n"
"optionally else branch if value is false.\n"
"e.g.: if (a>b) return a; else return b; then;"	),


// ----	instructions with immediate arguments -----------------------------

TOKEN(tIF,		pInstr,		"if",		"if n … [else …] then",
"execute statements only if value is true.\n"
"optionally else branch if value is false.\n"
"e.g.: if (a>b) return a; else return b; then;"	),

TOKEN(tELSE,	pInstr,		"else",		"if n … [else …] then",
"execute statements only if value is true.\n"
"optionally else branch if value is false.\n"
"e.g.: if (a>b) return a; else return b; then;"	),

TOKEN(tWHILE,	pInstr,		"while",	"do … while n … loop",
"repeat statements between do and loop while value is true.\n"
"e.g.: var i=1; do; while i<100; i+=i; loop; log i;" ),

TOKEN(tUNTIL,	pInstr,		"until",	"do … until n … loop",
"repeat statements between do and loop until value becomes true.\n"
"e.g.: var i=1; do; until i>100; i+=i; loop; log i;" ),

TOKEN(tEXIT,	pInstr,		"exit",		"do … exit … loop",
"exit from do…loop.\n"
"e.g.: var i=1; do; if i>100 exit then; i+=i; loop; log i;" ),

TOKEN(tNEXT,	pInstr,		"next",		"do … next … loop",
"immediately jump to start of do…loop for another go.\n"
"e.g.: var i=1; do; i+=i; if i<100 next then; exit; log \"never seen\" loop;" ),

TOKEN(tLOOP,	pInstr,		"loop",		"do … loop",
"repeat statements between do and loop.\n"
"e.g.: var i=1; do; put i; while i<10; i++; loop;" ),


// ----	special codes for temporary use ----------------------------------

TOKEN(tKOMM,		pAny,		"//",		"// … \\n",
"line comment: text up to end of line is a comment." ),

TOKEN(tKANF,		pAny,		"/*",		"/* … */",
"block comment: text between /* and */ is a comment." ),

TOKEN(tKEND,		pAny,		"*/",		"/* … */",
"block comment: text between /* and */ is a comment." )
};


#if TOKEN_PASS==1
const uint tokens =	tKEND+1;
#endif


#undef TOKEN_PASS
#undef TOKEN

#endif









