/* Tokens and token sequence arrays. */
%{
#include <nuttx/config.h>

#include <assert.h>
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>

#include "bas_auto.h"
#include "bas_token.h"
#include "bas_statement.h"

static int g_matchdata;
static int g_backslash_colon;
static int g_uppercase;
int yylex(void);
static struct Token *g_cur;

static void string(const char *text)
{
  if (g_cur)
  {
    const char *t;
    char *q;
    size_t l;

    for (t=text+1,l=0; *(t+1); ++t,++l)
    {
      if (*t=='"') ++t;
    }
    g_cur->u.string=malloc(sizeof(struct String));
    String_size(String_new(g_cur->u.string),l);
    for (t=text+1,q=g_cur->u.string->character; *(t+1); ++t,++q)
    {
      *q=*t;
      if (*t=='"') ++t;
    }
  }
}

static void string2(void)
{
  if (g_cur)
  {
    char *t,*q;
    size_t l;

    for (t=yytext+1,l=0; *t; ++t,++l)
    {
      if (*t=='"') ++t;
    }
    g_cur->u.string=malloc(sizeof(struct String));
    String_size(String_new(g_cur->u.string),l);
    for (t=yytext+1,q=g_cur->u.string->character; *t; ++t,++q)
    {
      *q=*t;
      if (*t=='"') ++t;
    }
  }
}

%}
 /* flex options and definitions */
%option noyywrap
%option nounput
%x DATAINPUT ELSEIF IMAGEFMT
REAL		([0-9]+("!"|"#"))|([0-9]+\.[0-9]*(e("+"|"-")?[0-9]+)?("!"|"#")?)|([0-9]*\.[0-9]+(e("+"|"-")?[0-9]+)?("!"|"#")?|([0-9]+e("+"|"-")?[0-9]+("!"|"#")?))
INTEGER		[0-9]+%?
HEXINTEGER	&H[0-9A-F]+
OCTINTEGER	&O[0-7]+
IDENTIFIER      ("fn"[ \t]+)?[A-Z][A-Z_0-9\.]*("$"|"%"|"#")?
STRING          \"([^"]|\"\")*\"
STRING2		\"([^"]|\"\")*$
REM		rem([^0-9A-Z_\.\n][^\n]*)?
QUOTE		("'"|"!")[^\n]*
ENDIF           end[ \t]*if
ENDPROC         end[ \t]*proc
ENDSELECT	end[ \t]*select
DOUNTIL		do[ \t]+until
DOWHILE		do[ \t]+while
EXITDO		exit[ \t]+do
EXITFOR		exit[ \t]+for
LINEINPUT	(line[ \t]+input)|linput
LOOPUNTIL	loop[ \t]+until
DATAITEM	[^ \t\n,:][^,:\n]*
ONERROR		on[ \t]+error
ONERROROFF	on[ \t]+error[ \t]+off
ONERRORGOTO0	on[ \t]+error[ \t]+goto[ \t]+0
SELECTCASE	select[ \t]+case

%%
 /* flex rules */
  if (g_matchdata) BEGIN(DATAINPUT);

"#"			return T_CHANNEL;
{REAL}          	{
			  int overflow;
			  double d;

                	  d=Value_vald(yytext,(char**)0,&overflow);
                	  if (overflow)
			  {
			    if (g_cur) g_cur->u.junk=yytext[0];
			    yyless(1);
			    return T_JUNK;
			  }
			  if (g_cur) g_cur->u.real=d;
                	  return T_REAL;
                	}
{INTEGER}       	{
			  int overflow;
			  long int n;

                	  n=Value_vali(yytext,(char**)0,&overflow);
			  if (overflow)
			  {
			    double d;

			    d=Value_vald(yytext,(char**)0,&overflow);
			    if (overflow)
			    {
			      if (g_cur) g_cur->u.junk=yytext[0];
			      yyless(1);
			      return T_JUNK;
			    }
			    if (g_cur) g_cur->u.real=d;
			    return T_REAL;
			  }
                	  if (g_cur) g_cur->u.integer=n;
                  	  return T_INTEGER;
                	}
{HEXINTEGER}    	{
			  int overflow;
			  long int n;

			  n=Value_vali(yytext,(char**)0,&overflow);
                	  if (overflow)
                	  {
                	    if (g_cur) g_cur->u.junk=yytext[0];
                	    yyless(1);
                            return T_JUNK;
                	  }
                	  if (g_cur) g_cur->u.hexinteger=n;
                	  return T_HEXINTEGER;
                	}
{OCTINTEGER}    	{
			  int overflow;
			  long int n;

                	  n=Value_vali(yytext,(char**)0,&overflow);
                	  if (overflow)
                	  {
                	    if (g_cur) g_cur->u.junk=yytext[0];
                	    yyless(1);
                            return T_JUNK;
                	  }
                	  if (g_cur) g_cur->u.octinteger=n;
                	  return T_OCTINTEGER;
                	}
{STRING}        	string(yytext); return T_STRING;
{STRING2}       	string2(); return T_STRING;
"("|"["             	return T_OP;
")"|"]"             	return T_CP;
"*"             	return T_MULT;
"+"             	return T_PLUS;
"-"             	return T_MINUS;
","             	return T_COMMA;
"/"             	return T_DIV;
"\\"			{
                          if (g_backslash_colon)
                          {
                            if (g_cur) g_cur->statement=stmt_COLON_EOL;
                            return T_COLON;
                          }
                          return T_IDIV;
                        }
":"             	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_COLON_EOL;
                          }
                          return T_COLON;
                        }
";"             	return T_SEMICOLON;
"<"             	return T_LT;
"<="            	return T_LE;
"=<"            	return T_LE;
"<>"|"><"            	return T_NE;
"="             	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_EQ_FNRETURN_FNEND;
                          }
                          return T_EQ;
                        }
">"             	return T_GT;
">="            	return T_GE;
"=>"            	return T_GE;
"^"             	return T_POW;
"access"[ \t]+"read"    return T_ACCESS_READ;
"access"[ \t]+"read"[ \t]+"write"    return T_ACCESS_READ_WRITE;
"access"[ \t]+"write"   return T_ACCESS_WRITE;
"and"			return T_AND;
"as"			return T_AS;
"call"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_CALL;
                          }
                          return T_CALL;
                        }
"case"[ \t]+"else"	{
			  if (g_cur)
			  {
			    g_cur->statement=stmt_CASE;
			    g_cur->u.casevalue=malloc(sizeof(struct Casevalue));
			  }
			  return T_CASEELSE;
			}
"case"			{
			  if (g_cur)
			  {
			    g_cur->statement=stmt_CASE;
			    g_cur->u.casevalue=malloc(sizeof(struct Casevalue));
			  }
			  return T_CASEVALUE;
			}
"chdir"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_CHDIR_MKDIR;
                          }
                          return T_CHDIR;
                        }
"clear"         	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_CLEAR;
                          }
                          return T_CLEAR;
                        }
"close"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_CLOSE;
                          }
                          return T_CLOSE;
                        }
"close"/"#"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_CLOSE;
                          }
                          return T_CLOSE;
                        }
"cls"|"home"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_CLS;
                          }
                          return T_CLS;
                        }
"color"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_COLOR;
                          }
                          return T_COLOR;
                        }
"con"			return T_CON;
"copy"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_COPY_RENAME;
                          }
                          return T_COPY;
                        }
"data"|"d."		{
                          BEGIN(DATAINPUT);
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DATA;
                          }
                          return T_DATA;
                        }
<DATAINPUT>{STRING}	string(yytext); return T_STRING;
<DATAINPUT>{STRING2}	string2(); return T_STRING;
<DATAINPUT>","		return T_COMMA;
<DATAINPUT>{DATAITEM}	{
	                  if (g_cur) g_cur->u.datainput=strcpy(malloc(strlen(yytext)+1),yytext);
			  return T_DATAINPUT;
			}
<DATAINPUT>[ \t]+
<DATAINPUT>\n		BEGIN(INITIAL);
<DATAINPUT>:		BEGIN(INITIAL); return T_COLON;
"dec"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DEC_INC;
                          }
                          return T_DEC;
                        }
"defdbl"        	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DEFINT_DEFDBL_DEFSTR;
                          }
                          return T_DEFDBL;
                        }
"defint"        	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DEFINT_DEFDBL_DEFSTR;
                          }
                          return T_DEFINT;
                        }
"defstr"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DEFINT_DEFDBL_DEFSTR;
                          }
                          return T_DEFSTR;
                        }
"def"/[ \t]+fn[ \t]*[A-Z_0-9\.] {
	                  if (g_cur)
	                  {
	                    g_cur->statement=stmt_DEFFN_DEFPROC_FUNCTION_SUB;
	                    g_cur->u.localSyms=(struct Symbol*)0;
	                  }
	                  return T_DEFFN;
	                }
"def"/[ \t]+proc[A-Z_0-9\.] {
	                  if (g_cur)
	                  {
	                    g_cur->statement=stmt_DEFFN_DEFPROC_FUNCTION_SUB;
	                    g_cur->u.localSyms=(struct Symbol*)0;
	                  }
	                  return T_DEFPROC;
	                }
"delete"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DELETE;
                          }
                          return T_DELETE;
                        }
"dim"           	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DIM;
                          }
                          return T_DIM;
                        }
"display"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DISPLAY;
                          }
                          return T_DISPLAY;
                        }
"do"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DO;
                          }
                          return T_DO;
                        }
{DOUNTIL}		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DOcondition;
                          }
                          return T_DOUNTIL;
                        }
{DOWHILE}		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DOcondition;
                          }
                          return T_DOWHILE;
                        }
"edit"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_EDIT;
                          }
                          return T_EDIT;
                        }
"else"|"el."		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ELSE_ELSEIFELSE;
                          }
                          return T_ELSE;
                        }
"else"/"if"		{
                          BEGIN(ELSEIF);
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ELSE_ELSEIFELSE;
                          }
                          return T_ELSEIFELSE;
                        }
<ELSEIF>"if"		{
                          BEGIN(INITIAL);
                          if (g_cur)
                          {
                            g_cur->statement=stmt_IF_ELSEIFIF;
                          }
                          return T_ELSEIFIF;
                        }
end[ \t]+function	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ENDFN;
                          }
                          return T_ENDFN;
                        }
{ENDIF}         	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ENDIF;
                          }
                          return T_ENDIF;
                        }
{ENDPROC}		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ENDPROC_SUBEND;
                          }
                          return T_ENDPROC;
                        }
{ENDSELECT}		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ENDSELECT;
                          }
                          return T_ENDSELECT;
                        }
"end"[ \t]*"sub"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ENDPROC_SUBEND;
                          }
                          return T_SUBEND;
                        }
"end"           	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_END;
                          }
                          return T_END;
                        }
"environ"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ENVIRON;
                          }
                          return T_ENVIRON;
                        }
"erase"         	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ERASE;
                          }
                          return T_ERASE;
                        }
"eqv"			return T_EQV;
{EXITDO}		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_EXITDO;
                          }
                          return T_EXITDO;
                        }
{EXITFOR}		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_EXITFOR;
                          }
                          return T_EXITFOR;
                        }
"exit"[ \t]+"function"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_FNEXIT;
                          }
                          return T_FNEXIT;
                        }
"exit"[ \t]+"sub"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_SUBEXIT;
                          }
                          return T_SUBEXIT;
                        }
"field"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_FIELD;
                          }
                          return T_FIELD;
                        }
"field"/"#"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_FIELD;
                          }
                          return T_FIELD;
                        }
"fnend"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_EQ_FNRETURN_FNEND;
                          }
                          return T_FNEND;
                        }
"fnreturn"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_EQ_FNRETURN_FNEND;
                          }
                          return T_FNRETURN;
                        }
"for"           	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_FOR;
                          }
                          return T_FOR;
                        }
"for"[ \t]+"input"      return T_FOR_INPUT;
"for"[ \t]+"output"     return T_FOR_OUTPUT;
"for"[ \t]+"append"     return T_FOR_APPEND;
"for"[ \t]+"random"     return T_FOR_RANDOM;
"for"[ \t]+"binary"     return T_FOR_BINARY;
"function"		{
	                  if (g_cur)
	                  {
	                    g_cur->statement=stmt_DEFFN_DEFPROC_FUNCTION_SUB;
	                    g_cur->u.localSyms=(struct Symbol*)0;
	                  }
	                  return T_FUNCTION;
	                }
"get"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_GET_PUT;
                          }
                          return T_GET;
                        }
"get"/"#"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_GET_PUT;
                          }
                          return T_GET;
                        }
"go"[ \t]*"sub"        	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_GOSUB;
                          }
                          return T_GOSUB;
                        }
"go"[ \t]*"to"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_RESUME_GOTO;
                          }
                          return T_GOTO;
                        }
"idn"			return T_IDN;
"if"            	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_IF_ELSEIFIF;
                          }
                          return T_IF;
                        }
"image"[ \t]*/[^"\n \t]	{
			  BEGIN(IMAGEFMT);
                	  if (g_cur)
                	  {
                	    g_cur->statement=stmt_IMAGE;
                	  }
                	  return T_IMAGE;
			}
<IMAGEFMT>.*$		{
			  BEGIN(INITIAL);
                	  if (g_cur)
                	  {
                            size_t l;

                	    l=strlen(yytext);
                            g_cur->u.string=malloc(sizeof(struct String));
                            String_size(String_new(g_cur->u.string),l);
                            memcpy(g_cur->u.string->character,yytext,l);
                	  }
                	  return T_STRING;
                	}
"image"			{
                	  if (g_cur)
                	  {
                	    g_cur->statement=stmt_IMAGE;
                	  }
                	  return T_IMAGE;
                	}
"imp"			return T_IMP;
"inc"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_DEC_INC;
                          }
                          return T_INC;
                        }
"input"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_INPUT;
                          }
                          return T_INPUT;
                        }
"input"/"#"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_INPUT;
                          }
                          return T_INPUT;
                        }
"inv"			return T_INV;
"is"			return T_IS;
"kill"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_KILL;
                          }
                          return T_KILL;
                        }
"let"           	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LET;
                          }
                          return T_LET;
                        }
"list"          	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LIST_LLIST;
                          }
                          return T_LIST;
                        }
"llist"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LIST_LLIST;
                          }
                          return T_LLIST;
                        }
"load"          	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LOAD;
                          }
                          return T_LOAD;
                        }
"local"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LOCAL;
                          }
                          return T_LOCAL;
                        }
"locate"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LOCATE;
                          }
                          return T_LOCATE;
                        }
"lock"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LOCK_UNLOCK;
                          }
                          return T_LOCK;
                        }
"lock"[ \t]+"read"	return T_LOCK_READ;
"lock"[ \t]+"write"	return T_LOCK_WRITE;
"loop"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LOOP;
                          }
                          return T_LOOP;
                        }
{LOOPUNTIL}		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LOOPUNTIL;
                          }
                          return T_LOOPUNTIL;
                        }
"lprint"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_PRINT_LPRINT;
                          }
                          return T_LPRINT;
                        }
"lset"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LSET_RSET;
                          }
                          return T_LSET;
                        }
"mat"[ \t]+"input"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_MATINPUT;
                          }
                          return T_MATINPUT;
                        }
"mat"[ \t]+"print"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_MATPRINT;
                          }
                          return T_MATPRINT;
                        }
"mat"[ \t]+"read"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_MATREAD;
                          }
                          return T_MATREAD;
                        }
"mat"[ \t]+"redim"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_MATREDIM;
                          }
                          return T_MATREDIM;
                        }
"mat"[ \t]+"write"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_MATWRITE;
                          }
                          return T_MATWRITE;
                        }
"mat"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_MAT;
                          }
                          return T_MAT;
                        }
"mkdir"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_CHDIR_MKDIR;
                          }
                          return T_MKDIR;
                        }
"mod"           	return T_MOD;
"new"           	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_NEW;
                          }
                          return T_NEW;
                        }
"name"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_NAME;
                          }
                          return T_NAME;
                        }
"next"          	{
                  	  if (g_cur)
                  	  {
                            g_cur->statement=stmt_NEXT;
                  	    g_cur->u.next=malloc(sizeof(struct Next));
                  	  }
			  return T_NEXT;
                	}
"not"			return T_NOT;
{ONERROROFF}		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ONERROROFF;
                          }
                          return T_ONERROROFF;
                        }
{ONERRORGOTO0}		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ONERRORGOTO0;
                          }
                          return T_ONERRORGOTO0;
                        }
{ONERROR}		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ONERROR;
                          }
                          return T_ONERROR;
                        }
"on"			{
			  if (g_cur)
			  {
			    g_cur->statement=stmt_ON;
			    g_cur->u.on.pcLength=1;
			    g_cur->u.on.pc=(struct Pc*)0;
			  }
			  return T_ON;
			}
"open"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_OPEN;
                          }
                          return T_OPEN;
                        }
"option"[ \t]+"base"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_OPTIONBASE;
                          }
                          return T_OPTIONBASE;
                        }
"option"[ \t]+"run"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_OPTIONRUN;
                          }
                          return T_OPTIONRUN;
                        }
"option"[ \t]+"stop"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_OPTIONSTOP;
                          }
                          return T_OPTIONSTOP;
                        }
"or"			return T_OR;
"out"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_OUT_POKE;
                          }
                          return T_OUT;
                        }
"print"|"p."|"?"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_PRINT_LPRINT;
                          }
                          return T_PRINT;
                        }
("print"|"p."|"?")/"#"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_PRINT_LPRINT;
                          }
                          return T_PRINT;
                        }
"poke"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_OUT_POKE;
                          }
                          return T_POKE;
                        }
"put"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_GET_PUT;
                          }
                          return T_PUT;
                        }
"put"/"#"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_GET_PUT;
                          }
                          return T_PUT;
                        }
"randomize"     	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_RANDOMIZE;
                          }
                          return T_RANDOMIZE;
                        }
"read"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_READ;
                          }
                          return T_READ;
                        }
"renum"|"ren."		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_RENUM;
                          }
                          return T_RENUM;
                        }
"repeat"|"rep."		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_REPEAT;
                          }
                          return T_REPEAT;
                        }
"restore"|"res."	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_RESTORE;
                          }
                          return T_RESTORE;
                        }
"resume"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_RESUME_GOTO;
                          }
                          return T_RESUME;
                        }
"return"|"r."   	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_RETURN;
                          }
                          return T_RETURN;
                        }
"rset"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LSET_RSET;
                          }
                          return T_RSET;
                        }
"run"           	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_RUN;
                          }
                          return T_RUN;
                        }
"save"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_SAVE;
                          }
                          return T_SAVE;
                        }
{SELECTCASE}		{
			  if (g_cur)
			  {
			    g_cur->statement=stmt_SELECTCASE;
			    g_cur->u.selectcase=malloc(sizeof(struct Selectcase));
			  }
			  return T_SELECTCASE;
			}
"shared"		return T_SHARED;
"shell"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_SHELL;
                          }
                          return T_SHELL;
                        }
"sleep"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_SLEEP;
                          }
                          return T_SLEEP;
                        }
"spc"			return T_SPC;
"step"          	return T_STEP;
"stop"          	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_STOP;
                          }
                          return T_STOP;
                        }
"sub"[ \t]*"end"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ENDPROC_SUBEND;
                          }
                          return T_SUBEND;
                        }
"sub"[ \t]*"exit"	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_SUBEXIT;
                          }
                          return T_SUBEXIT;
                        }
"sub"			{
	                  if (g_cur)
	                  {
	                    g_cur->statement=stmt_DEFFN_DEFPROC_FUNCTION_SUB;
	                    g_cur->u.localSyms=(struct Symbol*)0;
	                  }
	                  return T_SUB;
	                }
"swap"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_SWAP;
                          }
                          return T_SWAP;
                        }
"system"|"bye"        	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_SYSTEM;
                          }
                          return T_SYSTEM;
                        }
"then"|"th."		return T_THEN;
"tab"			return T_TAB;
"to"            	return T_TO;
"trn"			return T_TRN;
"troff"         	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_TROFF;
                          }
                          return T_TROFF;
                        }
"tron"          	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_TRON;
                          }
                          return T_TRON;
                        }
"truncate"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_TRUNCATE;
                          }
                          return T_TRUNCATE;
                        }
"unlock"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LOCK_UNLOCK;
                          }
                          return T_UNLOCK;
                        }
"unnum"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_UNNUM;
                          }
                          return T_UNNUM;
                        }
"until"         	{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_UNTIL;
                          }
                          return T_UNTIL;
                        }
"using"			return T_USING;
"wait"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_WAIT;
                          }
                          return T_WAIT;
                        }
"wend"          	{
                	  if (g_cur)
                	  {
                	    g_cur->statement=stmt_WEND;
                	    g_cur->u.whilepc=malloc(sizeof(struct Pc));
                	  }
                	  return T_WEND;
                	}
"while"         	{
                	  if (g_cur)
                	  {
                	    g_cur->statement=stmt_WHILE;
                	    g_cur->u.afterwend=malloc(sizeof(struct Pc));
                	  }
                	  return T_WHILE;
                	}
"width"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_WIDTH;
                          }
                          return T_WIDTH;
                        }
"width"/"#"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_WIDTH;
                          }
                          return T_WIDTH;
                        }
"write"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_WRITE;
                          }
                          return T_WRITE;
                        }
"write"/"#"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_WRITE;
                          }
                          return T_WRITE;
                        }
"xor"			return T_XOR;
"xref"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_XREF;
                          }
                          return T_XREF;
                        }
"zer"			return T_ZER;
"zone"			{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_ZONE;
                          }
                          return T_ZONE;
                        }
{REM}           	{
                	  if (g_cur)
                	  {
                	    g_cur->statement=stmt_QUOTE_REM;
                	    g_cur->u.rem=strcpy(malloc(strlen(yytext+3)+1),yytext+3);
                	  }
                	  return T_REM;
                	}
"rename"		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_COPY_RENAME;
                          }
                          return T_RENAME;
                        }
{QUOTE}          	{
                	  if (g_cur)
                	  {
                	    g_cur->statement=stmt_QUOTE_REM;
                	    strcpy(g_cur->u.rem=malloc(strlen(yytext+1)+1),yytext+1);
                          }	
                	  return T_QUOTE;
                	}
{LINEINPUT}		{
                          if (g_cur)
                          {
                            g_cur->statement=stmt_LINEINPUT;
                          }
                          return T_LINEINPUT;
                        }
{IDENTIFIER}		{
			  if (g_cur)
			  {
                            size_t len;
                            char *s;
                            int fn;

                            g_cur->statement=stmt_IDENTIFIER;
                            if (tolower(yytext[0])=='f' && tolower(yytext[1])=='n')
                            {
                              for (len=2,s=&yytext[2]; *s==' ' || *s=='\t'; ++s);
                              fn=1;
                            }
                            else
                            {
                              len=0;
                              s=yytext;
                              fn=0;
                            }
                            len+=strlen(s);
			    g_cur->u.identifier=malloc(offsetof(struct Identifier,name)+len+1);
                            if (fn)
                            {
                              memcpy(g_cur->u.identifier->name,yytext,2);
                              strcpy(g_cur->u.identifier->name+2,s);
                            }
                            else
                            {
                              strcpy(g_cur->u.identifier->name,s);
                            }
			    switch (yytext[yyleng-1])
			    {
			      case '$': g_cur->u.identifier->defaultType=V_STRING; break;
			      case '%': g_cur->u.identifier->defaultType=V_INTEGER; break;
			      default: g_cur->u.identifier->defaultType=V_REAL; break;
			    }
			  }
			  return T_IDENTIFIER;
			}
[ \t\n]+
.			{
			  if (g_cur) g_cur->u.junk=yytext[0];
			  return T_JUNK;
			}

%%

int g_token_property[T_LASTTOKEN];

struct Token *Token_newCode(const char *ln)
{
  int l,lasttok,thistok,addNumber=0,sawif;
  struct Token *result;
  YY_BUFFER_STATE buf;

  g_cur=(struct Token*)0;
  buf=yy_scan_string(ln);
  /* determine number of tokens */
  g_matchdata=sawif=0;
  for (lasttok=T_EOL,l=1; (thistok=yylex()); ++l)
  {
    if (l==1 && thistok!=T_INTEGER) { addNumber=1; ++l; }
    if ((lasttok==T_THEN || lasttok==T_ELSE) && thistok==T_INTEGER) ++l;
    if (thistok==T_IF) sawif=1;
    if (thistok==T_THEN) sawif=0;
    if (thistok==T_GOTO && sawif) ++l;
    lasttok=thistok;
  }
  if (l==1) { addNumber=1; ++l; }

  yy_delete_buffer(buf);
  g_cur=result=malloc(sizeof(struct Token)*l);
  if (addNumber)
  {
    g_cur->type=T_UNNUMBERED;
    ++g_cur;
  }
  buf=yy_scan_string(ln);
  lasttok=T_EOL;
  g_matchdata=sawif=0;
  while (g_cur->statement=NULL,(g_cur->type=yylex()))
  {
    if (g_cur->type==T_IF) sawif=1;
    if (g_cur->type==T_THEN) sawif=0;
    if (g_cur->type==T_GOTO && sawif)
    {
      sawif=0;
      *(g_cur+1)=*g_cur;
      g_cur->type=T_THEN;
      lasttok=T_GOTO;
      g_cur+=2;
    }
    else if ((lasttok==T_THEN || lasttok==T_ELSE) && g_cur->type==T_INTEGER)
    {
      *(g_cur+1)=*g_cur;
      g_cur->type=T_GOTO;
      g_cur->statement=stmt_RESUME_GOTO;
      lasttok=T_INTEGER;
      g_cur+=2;
    }
    else
    {
      lasttok=g_cur->type;
      ++g_cur;
    }
  }
  g_cur->type=T_EOL;
  g_cur->statement=stmt_COLON_EOL;
  yy_delete_buffer(buf);
  return result;
}

struct Token *Token_newData(const char *ln)
{
  int l;
  struct Token *result;
  YY_BUFFER_STATE buf;

  g_cur=(struct Token*)0;
  buf=yy_scan_string(ln);
  g_matchdata=1;
  for (l=1; yylex(); ++l);
  yy_delete_buffer(buf);
  g_cur=result=malloc(sizeof(struct Token)*l);
  buf=yy_scan_string(ln);
  g_matchdata=1;
  while (g_cur->statement=NULL,(g_cur->type=yylex())) ++g_cur;
  g_cur->type=T_EOL;
  g_cur->statement=stmt_COLON_EOL;
  yy_delete_buffer(buf);
  return result;
}

void Token_destroy(struct Token *token)
{
  struct Token *r=token;

  do
  {
    switch (r->type)
    {
      case T_ACCESS_READ:       break;
      case T_ACCESS_WRITE:      break;
      case T_AND:               break;
      case T_AS:                break;
      case T_CALL:              break;
      case T_CASEELSE:
      case T_CASEVALUE:         free(r->u.casevalue); break;
      case T_CHANNEL:           break;
      case T_CHDIR:             break;
      case T_CLEAR:             break;
      case T_CLOSE:             break;
      case T_CLS:               break;
      case T_COLON:             break;
      case T_COLOR:             break;
      case T_COMMA:             break;
      case T_CON:               break;
      case T_COPY:              break;
      case T_CP:                break;
      case T_DATA:              break;
      case T_DATAINPUT:         free(r->u.datainput); break;
      case T_DEC:               break;
      case T_DEFFN:             break;
      case T_DEFDBL:            break;
      case T_DEFINT:            break;
      case T_DEFPROC:           break;
      case T_DEFSTR:            break;
      case T_DELETE:            break;
      case T_DIM:               break;
      case T_DISPLAY:           break;
      case T_DIV:               break;
      case T_DO:                break;
      case T_DOUNTIL:           break;
      case T_DOWHILE:           break;
      case T_EDIT:              break;
      case T_ELSE:              break;
      case T_ELSEIFELSE:        break;
      case T_ELSEIFIF:          break;
      case T_END:               break;
      case T_ENDFN:             break;
      case T_ENDIF:             break;
      case T_ENDPROC:           break;
      case T_ENDSELECT:         break;
      case T_ENVIRON:           break;
      case T_EOL:               break;
      case T_EQ:                break;
      case T_EQV:               break;
      case T_ERASE:             break;
      case T_EXITDO:            break;
      case T_EXITFOR:           break;
      case T_FIELD:             break;
      case T_FNEND:             break;
      case T_FNEXIT:            break;
      case T_FNRETURN:          break;
      case T_FOR:               break;
      case T_FOR_INPUT:         break;
      case T_FOR_OUTPUT:        break;
      case T_FOR_APPEND:        break;
      case T_FOR_RANDOM:        break;
      case T_FOR_BINARY:        break;
      case T_FUNCTION:          break;
      case T_GE:                break;
      case T_GET:               break;
      case T_GOSUB:             break;
      case T_GOTO:              break;
      case T_GT:                break;
      case T_HEXINTEGER:        break;
      case T_OCTINTEGER:        break;
      case T_IDENTIFIER:        free(r->u.identifier); break;
      case T_IDIV:              break;
      case T_IDN:               break;
      case T_IF:                break;
      case T_IMAGE:             break;
      case T_IMP:               break;
      case T_INC:               break;
      case T_INPUT:             break;
      case T_INTEGER:           break;
      case T_INV:               break;
      case T_IS:                break;
      case T_JUNK:              break;
      case T_KILL:              break;
      case T_LE:                break;
      case T_LET:               break;
      case T_LINEINPUT:         break;
      case T_LIST:              break;
      case T_LLIST:             break;
      case T_LOAD:              break;
      case T_LOCAL:             break;
      case T_LOCATE:            break;
      case T_LOCK:              break;
      case T_LOCK_READ:         break;
      case T_LOCK_WRITE:        break;
      case T_LOOP:              break;
      case T_LOOPUNTIL:         break;
      case T_LPRINT:            break;
      case T_LSET:              break;
      case T_LT:                break;
      case T_MAT:               break;
      case T_MATINPUT:          break;
      case T_MATPRINT:          break;
      case T_MATREAD:           break;
      case T_MATREDIM:          break;
      case T_MATWRITE:          break;
      case T_MINUS:             break;
      case T_MKDIR:             break;
      case T_MOD:               break;
      case T_MULT:              break;
      case T_NAME:              break;
      case T_NE:                break;
      case T_NEW:               break;
      case T_NEXT:              free(r->u.next); break;
      case T_NOT:               break;
      case T_ON:                if (r->u.on.pc) free(r->u.on.pc); break;
      case T_ONERROR:           break;
      case T_ONERRORGOTO0:      break;
      case T_ONERROROFF:        break;
      case T_OP:                break;
      case T_OPEN:              break;
      case T_OPTIONBASE:        break;
      case T_OPTIONRUN:         break;
      case T_OPTIONSTOP:        break;
      case T_OR:                break;
      case T_OUT:		break;
      case T_PLUS:              break;
      case T_POKE:		break;
      case T_POW:               break;
      case T_PRINT:             break;
      case T_PUT:               break;
      case T_QUOTE:             free(r->u.rem); break;
      case T_RANDOMIZE:         break;
      case T_READ:              break;
      case T_REAL:              break;
      case T_REM:               free(r->u.rem); break;
      case T_RENAME:            break;
      case T_RENUM:             break;
      case T_REPEAT:            break;
      case T_RESTORE:           break;
      case T_RESUME:            break;
      case T_RETURN:            break;
      case T_RSET:              break;
      case T_RUN:               break;
      case T_SAVE:              break;
      case T_SELECTCASE:        free(r->u.selectcase); break;
      case T_SEMICOLON:         break;
      case T_SHARED:            break;
      case T_SHELL:             break;
      case T_SLEEP:             break;
      case T_SPC:               break;
      case T_STEP:              break;
      case T_STOP:              break;
      case T_STRING:            String_destroy(r->u.string); free(r->u.string); break;
      case T_SUB:               break;
      case T_SUBEND:            break;
      case T_SUBEXIT:           break;
      case T_SWAP:              break;
      case T_SYSTEM:            break;
      case T_TAB:               break;
      case T_THEN:              break;
      case T_TO:                break;
      case T_TRN:               break;
      case T_TROFF:             break;
      case T_TRON:              break;
      case T_TRUNCATE:          break;
      case T_UNLOCK:            break;
      case T_UNNUM:             break;
      case T_UNNUMBERED:        break;
      case T_UNTIL:             break;
      case T_USING:             break;
      case T_WAIT:              break;
      case T_WEND:              free(r->u.whilepc); break;
      case T_WHILE:             free(r->u.afterwend); break;
      case T_WIDTH:             break;
      case T_WRITE:             break;
      case T_XOR:               break;
      case T_XREF:              break;
      case T_ZER:               break;
      case T_ZONE:              break;
      default:                  assert(0);
    }
  } while ((r++)->type!=T_EOL);
  free(token);
}

struct String *Token_toString(struct Token *token, struct Token *spaceto, struct String *s, int *indent, int width)
{
  int ns=0,infn=0;
  int thisindent=0,thisnotindent=0,nextindent=0;
  size_t oldlength=s->length;
  struct Token *t;
  static struct
  {
    const char *text;
    char space;
  } table[]=
  {
    /* 0                    */ {(const char*)0,-1},
    /* T_ACCESS_READ        */ {"access read",1},
    /* T_ACCESS_READ_WRITE  */ {"access read write",1},
    /* T_ACCESS_WRITE       */ {"access write",1},
    /* T_AND                */ {"and",1},
    /* T_AS                 */ {"as",1},
    /* T_CALL               */ {"call",1},
    /* T_CASEELSE           */ {"case else",1},
    /* T_CASEVALUE          */ {"case",1},
    /* T_CHANNEL            */ {"#",0},
    /* T_CHDIR              */ {"chdir",1},
    /* T_CLEAR              */ {"clear",1},
    /* T_CLOSE              */ {"close",1},
    /* T_CLS                */ {"cls",1},
    /* T_COLON              */ {":",1},
    /* T_COLOR              */ {"color",1},
    /* T_COMMA              */ {",",0},
    /* T_CON                */ {"con",0},
    /* T_COPY               */ {"copy",1},
    /* T_CP                 */ {")",0},
    /* T_DATA               */ {"data",1},
    /* T_DATAINPUT          */ {(const char*)0,0},
    /* T_DEC                */ {"dec",1},
    /* T_DEFDBL             */ {"defdbl",1},
    /* T_DEFFN              */ {"def",1},
    /* T_DEFINT             */ {"defint",1},
    /* T_DEFPROC            */ {"def",1},
    /* T_DEFSTR             */ {"defstr",1},
    /* T_DELETE             */ {"delete",1},
    /* T_DIM                */ {"dim",1},
    /* T_DISPLAY            */ {"display",1},
    /* T_DIV                */ {"/",0},
    /* T_DO                 */ {"do",1},
    /* T_DOUNTIL            */ {"do until",1},
    /* T_DOWHILE            */ {"do while",1},
    /* T_EDIT               */ {"edit",1},
    /* T_ELSE               */ {"else",1},
    /* T_ELSEIFELSE         */ {"elseif",1},
    /* T_ELSEIFIF           */ {(const char*)0,0},
    /* T_END                */ {"end",1},
    /* T_ENDFN              */ {"end function",1},
    /* T_ENDIF              */ {"end if",1},
    /* T_ENDPROC            */ {"end proc",1},
    /* T_ENDSELECT          */ {"end select",1},
    /* T_ENVIRON            */ {"environ",1},
    /* T_EOL                */ {"\n",0},
    /* T_EQ                 */ {"=",0},
    /* T_EQV                */ {"eqv",0},
    /* T_ERASE              */ {"erase",1},
    /* T_EXITDO             */ {"exit do",1},
    /* T_EXITFOR            */ {"exit for",1},
    /* T_FIELD              */ {"field",1},
    /* T_FNEND              */ {"fnend",1},
    /* T_FNEXIT             */ {"exit function",1},
    /* T_FNRETURN           */ {"fnreturn",1},
    /* T_FOR                */ {"for",1},
    /* T_FOR_INPUT          */ {"for input",1},
    /* T_FOR_OUTPUT         */ {"for output",1},
    /* T_FOR_APPEND         */ {"for append",1},
    /* T_FOR_RANDOM         */ {"for random",1},
    /* T_FOR_BINARY         */ {"for binary",1},
    /* T_FUNCTION           */ {"function",1},
    /* T_GE                 */ {">=",0},
    /* T_GET                */ {"get",1},
    /* T_GOSUB              */ {"gosub",1},
    /* T_GOTO               */ {"goto",1},
    /* T_GT                 */ {">",0},
    /* T_HEXINTEGER         */ {(const char*)0,0},
    /* T_OCTINTEGER         */ {(const char*)0,0},
    /* T_IDENTIFIER         */ {(const char*)0,0},
    /* T_IDIV               */ {"\\",0},
    /* T_IDN                */ {"idn",0},
    /* T_IF                 */ {"if",1},
    /* T_IMAGE              */ {"image",1},
    /* T_IMP                */ {"imp",0},
    /* T_INC                */ {"inc",1},
    /* T_INPUT              */ {"input",1},
    /* T_INTEGER            */ {(const char*)0,0},
    /* T_INV                */ {"inv",0},
    /* T_IS                 */ {"is",1},
    /* T_JUNK               */ {(const char*)0,0},
    /* T_KILL               */ {"kill",1},
    /* T_LE                 */ {"<=",0},
    /* T_LET                */ {"let",1},
    /* T_LINEINPUT          */ {"line input",1},
    /* T_LIST               */ {"list",1},
    /* T_LLIST              */ {"llist",1},
    /* T_LOAD               */ {"load",1},
    /* T_LOCAL              */ {"local",1},
    /* T_LOCATE             */ {"locate",1},
    /* T_LOCK               */ {"lock",1},
    /* T_LOCK_READ          */ {"lock read",1},
    /* T_LOCK_WRITE         */ {"lock write",1},
    /* T_LOOP               */ {"loop",1},
    /* T_LOOPUNTIL          */ {"loop until",1},
    /* T_LPRINT             */ {"lprint",1},
    /* T_LSET               */ {"lset",1},
    /* T_LT                 */ {"<",0},
    /* T_MAT                */ {"mat",1},
    /* T_MATINPUT           */ {"mat input",1},
    /* T_MATPRINT           */ {"mat print",1},
    /* T_MATREAD            */ {"mat read",1},
    /* T_MATREDIM           */ {"mat redim",1},
    /* T_MATWRITE           */ {"mat write",1},
    /* T_MINUS              */ {"-",0},
    /* T_MKDIR              */ {"mkdir",1},
    /* T_MOD                */ {"mod",0},
    /* T_MULT               */ {"*",0},
    /* T_NAME               */ {"name",1},
    /* T_NE                 */ {"<>",0},
    /* T_NEW                */ {"new",1},
    /* T_NEXT               */ {"next",1},
    /* T_NOT                */ {"not",0},
    /* T_ON                 */ {"on",1},
    /* T_ONERROR            */ {"on error",1},
    /* T_ONERRORGOTO0       */ {"on error goto 0",1},
    /* T_ONERROROFF         */ {"on error off",1},
    /* T_OP                 */ {"(",0},
    /* T_OPEN               */ {"open",1},
    /* T_OPTIONBASE         */ {"option base",1},
    /* T_OPTIONRUN          */ {"option run",1},
    /* T_OPTIONSTOP         */ {"option stop",1},
    /* T_OR                 */ {"or",1},
    /* T_OUT                */ {"out",1},
    /* T_PLUS               */ {"+",0},
    /* T_POKE               */ {"poke",1},
    /* T_POW                */ {"^",0},
    /* T_PRINT              */ {"print",1},
    /* T_PUT                */ {"put",1},
    /* T_QUOTE              */ {(const char*)0,1},
    /* T_RANDOMIZE          */ {"randomize",1},
    /* T_READ               */ {"read",1},
    /* T_REAL               */ {(const char*)0,0},
    /* T_REM                */ {(const char*)0,1},
    /* T_RENAME             */ {"rename",1},
    /* T_RENUM              */ {"renum",1},
    /* T_REPEAT             */ {"repeat",1},
    /* T_RESTORE            */ {"restore",1},
    /* T_RESUME             */ {"resume",1},
    /* T_RETURN             */ {"return",1},
    /* T_RSET               */ {"rset",1},
    /* T_RUN                */ {"run",1},
    /* T_SAVE               */ {"save",1},
    /* T_SELECTCASE         */ {"select case",1},
    /* T_SEMICOLON          */ {";",0},
    /* T_SHARED             */ {"shared",1},
    /* T_SHELL              */ {"shell",1},
    /* T_SLEEP              */ {"sleep",1},
    /* T_SPC                */ {"spc",0},
    /* T_STEP               */ {"step",1},
    /* T_STOP               */ {"stop",1},
    /* T_STRING             */ {(const char*)0,0},
    /* T_SUB                */ {"sub",1},
    /* T_SUBEND             */ {"subend",1},
    /* T_SUBEXIT            */ {"subexit",1},
    /* T_SWAP               */ {"swap",1},
    /* T_SYSTEM             */ {"system",1},
    /* T_TAB                */ {"tab",0},
    /* T_THEN               */ {"then",1},
    /* T_TO                 */ {"to",1},
    /* T_TRN                */ {"trn",0},
    /* T_TROFF              */ {"troff",1},
    /* T_TRON               */ {"tron",1},
    /* T_TRUNCATE           */ {"truncate",1},
    /* T_UNLOCK             */ {"unlock",1},
    /* T_UNNUM              */ {"unnum",1},
    /* T_UNNUMBERED         */ {"",0},
    /* T_UNTIL              */ {"until",1},
    /* T_USING              */ {"using",0},
    /* T_WAIT               */ {"wait",1},
    /* T_WEND               */ {"wend",1},
    /* T_WHILE              */ {"while",1},
    /* T_WIDTH              */ {"width",1},
    /* T_WRITE              */ {"write",1},
    /* T_XOR                */ {"xor",0},
    /* T_XREF               */ {"xref",0},
    /* T_ZER                */ {"zer",0},
    /* T_ZONE               */ {"zone",1},
  };

  /* precompute indentation */
  if (indent) thisindent=nextindent=*indent;
  t=token;
  do
  {
    switch (t->type)
    {
      case T_CASEELSE:
      case T_CASEVALUE:
      {
        if (thisnotindent) --thisnotindent; else if (thisindent) --thisindent;
        break;
      }
      case T_DEFFN:
      case T_FUNCTION:
      {
        struct Token *cp;

        for (cp=t; cp->type!=T_EOL && cp->type!=T_CP; ++cp);
        if ((cp+1)->type!=T_EQ)
        {
          ++thisnotindent;
          ++nextindent;
        }
        infn=1;
        break;
      }
      case T_COLON: infn=0; break;
      case T_DEFPROC:
      case T_DO:
      case T_DOUNTIL:
      case T_DOWHILE:
      case T_REPEAT:
      case T_SUB:
      case T_WHILE: ++thisnotindent; ++nextindent; break;
      case T_FOR:
      {
        if ((t>token && ((t-1)->type==T_COLON || (t-1)->type==T_INTEGER || (t-1)->type==T_UNNUMBERED)))
        {
          ++thisnotindent; ++nextindent;
        }
        break;
      } 
      case T_SELECTCASE: thisnotindent+=2; nextindent+=2; break;
      case T_EQ:
      {
        if (infn || (t>token && ((t-1)->type==T_COLON || (t-1)->type==T_INTEGER || (t-1)->type==T_UNNUMBERED)))
        {
          if (thisnotindent) --thisnotindent; else if (thisindent) --thisindent;
          if (nextindent) --nextindent;
        }
        infn=0;
        break;
      }
      case T_ENDFN:
      case T_FNEND:
      case T_ENDIF:
      case T_ENDPROC:
      case T_SUBEND:
      case T_LOOP:
      case T_LOOPUNTIL:
      case T_UNTIL:
      case T_WEND:
      {
        if (thisnotindent) --thisnotindent; else if (thisindent) --thisindent;
        if (nextindent) --nextindent;
        break;
      }
      case T_ENDSELECT:
      {
        if (thisnotindent) --thisnotindent; else if (thisindent) --thisindent;
        if (thisnotindent) --thisnotindent; else if (thisindent) --thisindent;
        if (nextindent) --nextindent;
        if (nextindent) --nextindent;
        break;
      }
      case T_NEXT:
      {
        ++t;
        while (1)
        {
          if (thisnotindent) --thisnotindent; else if (thisindent) --thisindent;
          if (nextindent) --nextindent;
          if (t->type==T_IDENTIFIER)
          {
            ++t;
            if (t->type==T_OP)
            {
              int par=0;

              do
              {
                if (t->type==T_OP) ++par;
                else if (t->type==T_CP) --par;
                if (t->type!=T_EOL) ++t;
                else break;
              } while (par);
            }
            if (t->type==T_COMMA) ++t;
            else break;
          }
          else break;
        }
        break;
      }
      case T_THEN: if ((t+1)->type==T_EOL) { ++thisnotindent; ++nextindent; } break;
      case T_ELSE:
      {
        if (t==token+1)
        {
          if (thisnotindent) --thisnotindent; else if (thisindent) --thisindent;
        }
        break;
      }
      case T_ELSEIFELSE:
      {
        if (t==token+1)
        {
          if (thisnotindent) --thisnotindent; else if (thisindent) --thisindent;
        }
        if (nextindent) --nextindent;
        break;
      }
      default: break;
    }
  } while (t++->type!=T_EOL);

  if (width>=0) /* whole line */
  {
    if (width) /* nicely formatted listing */
    {
      assert (token->type==T_UNNUMBERED || token->type==T_INTEGER);
      if (token->type==T_INTEGER) String_appendPrintf(s,"%*ld ",width,token->u.integer);
      else String_appendPrintf(s,"%*s ",width,"");
    }
    else assert (token->type==T_UNNUMBERED);
    ++token;
  }
  while (thisindent--) String_appendPrintf(s,"  ");
  do
  {
    if (s->length>oldlength && token->type!=T_EOL)
    {
      const char *keyword;

      if ((keyword=table[token->type].text)==(const char*)0) keyword="X";
      if (ns && s->character[s->length-1]!=' ')
      {
        String_appendPrintf(s," ");
      }
      else if (isalnum((int)(s->character[s->length-1])) && isalnum((int)*keyword))
      {
        String_appendPrintf(s," ");
      }
      else if (s->character[s->length-1]!=' ' && table[token->type].space)
      {
        String_appendChar(s,' ');
      }
    }
    if (spaceto && token==spaceto) break;
    switch (token->type)
    {
      case T_DATAINPUT: String_appendChars(s,token->u.datainput); break;
      case T_ELSEIFIF: break;
      case T_IDENTIFIER: String_appendChars(s,token->u.identifier->name); break;
      case T_INTEGER: String_appendPrintf(s,"%ld",token->u.integer); break;
      case T_HEXINTEGER: String_appendPrintf(s,"&h%lx",token->u.hexinteger); break;
      case T_OCTINTEGER: String_appendPrintf(s,"&o%lo",token->u.octinteger); break;
      case T_JUNK: String_appendChar(s,token->u.junk); break;
      case T_REAL:
      {
        String_appendPrintf(s,"%.*g",DBL_DIG,token->u.real);
        if ((token->u.real<((double)LONG_MIN)) || (token->u.real>((double)LONG_MAX))) String_appendChar(s,'!');
        break;
      }
      case T_REM: String_appendPrintf(s,"%s%s",g_uppercase?"REM":"rem",token->u.rem); break;
      case T_QUOTE: String_appendPrintf(s,"'%s",token->u.rem); break;
      case T_STRING:
      {
        size_t l=token->u.string->length;
        char *data=token->u.string->character;

        String_appendPrintf(s,"\"");
        while (l--)
        {
          if (*data=='"') String_appendPrintf(s,"\"");
          String_appendPrintf(s,"%c",*data);
          ++data;
        }
        String_appendPrintf(s,"\"");
        break;
      }

      default:
      {
        if (g_uppercase)
        {
          struct String u;

          String_new(&u);
          String_appendChars(&u,table[token->type].text);
          String_ucase(&u);
          String_appendString(s,&u);
          String_destroy(&u);
        }
        else String_appendChars(s,table[token->type].text);
      }
    }
    ns=table[token->type].space;
  } while (token++->type!=T_EOL);
  if (indent) *indent=nextindent;
  if (spaceto && s->length>oldlength) memset(s->character+oldlength,' ',s->length-oldlength);
  return s;
}

void Token_init(int b_c, int uc)
{
#define PROPERTY(t,assoc,unary_priority,binary_priority,is_unary,is_binary) \
  g_token_property[t]=(assoc<<8)|(unary_priority<<5)|(binary_priority<<2)|(is_unary<<1)|is_binary

  g_backslash_colon=b_c;
  g_uppercase=uc;
  PROPERTY(T_POW,  1,0,7,0,1);
  PROPERTY(T_MULT, 0,0,5,0,1);
  PROPERTY(T_DIV,  0,0,5,0,1);
  PROPERTY(T_IDIV, 0,0,5,0,1);
  PROPERTY(T_MOD,  0,0,5,0,1);
  PROPERTY(T_PLUS, 0,6,4,1,1);
  PROPERTY(T_MINUS,0,6,4,1,1);
  PROPERTY(T_LT,   0,0,3,0,1);
  PROPERTY(T_LE,   0,0,3,0,1);
  PROPERTY(T_EQ,   0,0,3,0,1);
  PROPERTY(T_GE,   0,0,3,0,1);
  PROPERTY(T_GT,   0,0,3,0,1);
  PROPERTY(T_NE,   0,0,3,0,1);
  PROPERTY(T_NOT,  0,2,0,1,0);
  PROPERTY(T_AND,  0,0,1,0,1);
  PROPERTY(T_OR,   0,0,0,0,1);
  PROPERTY(T_XOR,  0,0,0,0,1);
  PROPERTY(T_EQV,  0,0,0,0,1);
  PROPERTY(T_IMP,  0,0,0,0,1);
}

