/*****************************************************************
*  BASic Emulation Compiler (BASEC) by William Yu (c)1998-99
*  Please read and understand the GNU public license that applies
*  to this program and source code.
*
*  BEC.C Program Information:
*     BEC is the parser/byte-code generator for the BASEC language
*     VAR.LST will list all undeclared variables, it's a good
*     idea to use this list and place it at the beginning of your
*     program.
******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include "keywords.h"

/**
  Successfully compiled under DJGPP/GCC, and Borland C/C++,
  UNIX (Solaris, OpenBSD, SGI), LINUX Intel.
  DJGPP is more forgiving, but that can lead to weird errors.
**/

//#define USE_UNIX

#define MAXLINE    2048+1
#define MAX_TOKEN  80+1
#define VERSION    "v0.20"

struct ResolveType
  {
    byte  CNTRL_TAG;  /** Such as WHILE,FOR,IF, etc... **/
    int   lbc;        // length of byte code for GOTO
    int   iflbc;      // length of byte code for IF false
    word  var;
    bool  step_var;   // What's after STEP a variable?
    short int   step;
    dword address;
    dword gotoaddr;
    //struct ResolveType *next;
  }
  resolve[200];
int resolve_stack = 0;

struct labeltype
  {
    char* caption;
    dword address;
    //struct labeltype *next;
  }
  *labels = NULL,
  *gotos = NULL;
int labels_stack_top = 100, gotos_stack_top = 100;

/** REDIM PRESERVE **/
struct str_list
  {
    char *name;
    byte type;
  }
*charstack = NULL, *intstack = NULL, *arrcharstack = NULL, *arrintstack = NULL,
*conststack = NULL;

long int char_stack_top = 100, int_stack_top = 100,
         arrchar_stack_top = 100, arrint_stack_top = 100,
         const_stack_top = 100;

word max_strvar = 0, max_intvar = 0,
     max_arrstrvar = 0, max_arrintvar = 0,
     max_const = 0,
     max_labels = 0, max_gotos = 0;

FILE *fp, *fout, *datafile, *varlst;

dword line          = 0; /** Keep tabs on the current line number **/
dword len_byte_code = 0; /** Code length **/
dword len_data_seg  = 0;
dword bytes_data    = 0; /** This really serves no purpose... yet **/
int  rvalue,nobrace;
bool USE_DOS = FALSE;
bool USE_GRAPHICS = FALSE;
bool USE_MM = FALSE;
long int num_statements = 0;  /** What is a statement anyway? **/


/*** Declarations ***/

char*  rtrim(char *text);
int    read_line(char *text, int n);
int    get_token(char *text, char *token, int n);
int    parse_text(char *text, int start);
void   check_dupevar(char *variable);
void   expected(char *expect, char *text);
void   write_operator(int op);
int    priority (int operator);
void   process_operator(int operator, int op_stack[], int *stack_top);
int    process_paren(int op_stack[], int *stack_top);
int    get_expression(char *text, int n);
int    get_string_expression(char *text, int n);
int    write_expression(char *text, int i, int op_stack[], int *stack_top);
int    write_string_expression(char *text, int i, int op_stack[], int *stack_top);
void   probe_number(char *num);
int    probe_expression(char *text, int i);
void   add_intvar(char *variable, byte datatype);
void   add_strvar(char *variable);
void   add_arrintvar(char *variable, byte datatype);
void   add_arrstrvar(char *variable);
void   DIM_footprint(char *text, int *i);
void   DIM_inplace(char *variable);
void   IF_footprint(char *text, int *i);
void   ELSEIF_footprint(char *text, int *i);
void   print_string_expression(char *text, int *i);
void   print_integer_expression(char *text, int *i);
int    check_strvar(char *variable);
int    check_strarrvar(char *variable);
int    check_intvar(char *variable);
int    check_intarrvar(char *variable);
int    check_and_writeint(char *text, char *token, int i);
int    check_and_writestr(char *text, char *token, int i);
void   Read_DATA(char *text, int start);
int    write_variable(char *text, char *token, int i);
void   resolve_branches();

/*** End of declarations ***/

void add_gotos(char *variable, dword address)
  {
     if (max_gotos >= gotos_stack_top)
       {
         gotos_stack_top+=100;
         gotos = realloc(gotos, 4*gotos_stack_top);
       }
     gotos[max_gotos].caption = malloc(MAX_TOKEN);
     gotos[max_gotos].address = address;

     strcpy(gotos[max_gotos].caption,variable);
     max_gotos++;
  }
/** END ADD_GOTOS **/

void add_labels(char *variable, dword address)
  {
     if (max_labels >= labels_stack_top)
       {
         labels_stack_top+=100;
         labels = realloc(labels, 4*labels_stack_top);
       }
     labels[max_labels].caption = malloc(strlen(variable)+1);
     labels[max_labels].address = address;

     strcpy(labels[max_labels].caption,variable);
     max_labels++;
  }
/** END ADD_LABELS **/


int priority (int operator)
  {
  //'**********************************************************
  //'   Input:  The Character Operator
  //' Purpose:  Find the priority of Operator, and arithmetic
  //'           operator of (.
  //'  Output:  Returns priority (0 - 6) of Operator.
  //'**********************************************************
 
    switch (operator)
      {
        case '(':
          return 0;
        case 'X': case '&': case '|': case '~':
          return 1;
        case '=': case '<': case '>': case 'G': case 'L': case '!':
          return 2;
        case '+': case '-':
          return 3;
        case '%':
          return 4;
        case '*': case '/': case '\\':
          return 5;
        case '^':
          return 6;
      }

    return -1;  /** Should never reach this statement... **/
  }
/** END PRIORITY **/


void write_operator(int op)
  {
         //printf("%c\n",op);
         switch (op)
         {
             case '+':
               fputc(OP_ADD,fout);
               break;
             case '-':
               fputc(OP_MINUS,fout);
               break;
             case '*':
               fputc(OP_MULT,fout);
               break;
             case '/': case '\\':
               fputc(OP_DIVIDE,fout);
               break;
             case '^':
               fputc(OP_POWER,fout);
               break;
             case '%':
               fputc(OP_MOD,fout);
               break;
             case '&':
               fputc(OP_AND,fout);
               break;
             case '|':
               fputc(OP_OR,fout);
               break;
             case 'X':
               fputc(OP_XOR,fout);
               break;
             case '~':
               fputc(OP_NOT,fout);
               break;
             case '=':
               fputc(EX_EQUAL,fout);
               break;
             case '>':
               fputc(EX_GREATER,fout);
               break;
             case '<':
               fputc(EX_LESS,fout);
               break;
             case '!':
               fputc(EX_NOTEQUAL,fout);
               break;
             case 'G':
               fputc(EX_GREATEREQ,fout);
               break;
             case 'L':
               fputc(EX_LESSEQ,fout);
               break;
         }
         len_byte_code = len_byte_code + 1;
  }
/** END WRITE_OPERATOR **/


void process_operator(int operator, int op_stack[], int *stack_top)
  {
    int top_operator, done = FALSE;

    do
      {
        if (*stack_top == 0)
          done = TRUE;
        else
          {
            (*stack_top)--;
            top_operator = op_stack[*stack_top];
            if (priority(operator) <= priority(top_operator))
              {
                write_operator(top_operator);
              }
            else
              {
                op_stack[(*stack_top)++] = top_operator;
                done = TRUE;
              }
          }
      }
    while (done == FALSE);

    op_stack[(*stack_top)++] = operator;
  }
/** END PROCESS OPERATOR **/


int process_paren(int op_stack[], int *stack_top)
  {
    int toptoken;

    do
      {
        if (*stack_top == 0)
          {
            if (nobrace == TRUE)
               return -1;
            else
              {
                printf("Line %ld: Error in expression, missing parenthesis\n",line);
                exit(EXIT_FAILURE);
              }
          }
        else
          {
            (*stack_top)--;
            toptoken = op_stack[*stack_top];
            if (toptoken != '(') write_operator(toptoken);
         }
      }
    while (toptoken != '(');

    return 0;
  }
/** END PROCESS_PAREN **/


int get_expression(char *text, int n)
  {
    int i=n,done=0;
    int max=strlen(text);
    int ch,lastch=0;
    int op_stack[100], stack_top = 0;

    while (i < max && text[i] != ',' && text[i] != ';' && text[i] != ':' && text[i] != '\'')
      {
        ch = text[i];
        if (ch == 39) break;
        if (strchr("()+-*/^<>=\\", ch) != NULL)
          {
            switch (ch)
              {
                case '=':
                  if (text[i+1] == '>')
                    {
                      ch = 'G';
                      i++;
                    }
                  else if (text[i+1] == '<')
                    {
                      ch = 'L';
                      i++;
                    }
                  else
                    ch = '=';
                  process_operator(ch, op_stack, &stack_top);
                  break;
                case '<':
                  if (text[i+1] == '>')
                    {
                      ch = '!';
                      i++;
                    }
                  else if (text[i+1] == '=')
                    {
                      ch = 'L';
                      i++;
                    }
                  else
                    ch = '<';
                  process_operator(ch, op_stack, &stack_top);
                  break;
                case '>':
                  if (text[i+1] == '=')
                    {
                      ch = 'G';
                      i++;
                    }
                  else
                    ch = '>';
                  process_operator(ch, op_stack, &stack_top);
                  break;
               case '(':   // Push
                  lastch = 0;
                  op_stack[stack_top++] = '(';
                  break;
               case ')':
                  lastch = 0;
                  done = process_paren(op_stack, &stack_top);
                  break;
               case '+': case '-': case '*': case '/': case '^': case '\\':
                  // * * -15
                  if (lastch != 0)
                    {
                      if (ch != '*' && ch != '/' && ch != '^' && ch != '\\')
                        {
                          if (lastch == '-' && ch == '-')
                            {
                              if (stack_top > 0) op_stack[stack_top-1] = '+';
                              lastch = '+';
                            }
                          else
                            {
                              if (stack_top > 0) op_stack[stack_top-1] = '-';
                              lastch = '-';
                            }
                        }
                    }
                  else
                  {
                      lastch = ch;
                      process_operator(ch, op_stack, &stack_top);
                  }
                  break;
              }
              /** END SWITCH **/
          }
        else if (ch != 32)
        {
          lastch = 0;
          done = write_expression(text, i, op_stack, &stack_top);
          if (done != -1)
            i = done;
        }
        if (done == -1) break;
        i++;
      }
      /** END WHILE **/

  while (stack_top != 0)
    {
      stack_top--;
      ch = op_stack[stack_top];
      if (ch == '(')
        {
          printf("Line %ld: Error in expression, unresolved parenthesis\n",line);
          exit(EXIT_FAILURE);
        }
      else
        {
          write_operator(ch);
        }    
    }
    /** END WHILE **/

    fputc(DT_NONE,fout);
    len_byte_code = len_byte_code + 1;

    return i;
  }
/** END GET_EXPRESSION **/


int get_string_expression(char *text, int n)
  {
    int i=n,done=0;
    int max=strlen(text);
    int ch,lastch=0;
    int op_stack[100], stack_top = 0;

    while (i < max && text[i] != ',' && text[i] != ';' && text[i] != ':' && text[i] != '\'')
      {
        ch = text[i];
        if (ch == 39) break;
        if (strchr("()+-*/^<>=\\", ch) != NULL)
          {
            switch (ch)
              {
                case '=':
                  if (text[i+1] == '>')
                    {
                      ch = 'G';
                      i++;
                    }
                  else if (text[i+1] == '<')
                    {
                      ch = 'L';
                      i++;
                    }
                  else
                    ch = '=';
                  process_operator(ch, op_stack, &stack_top);
                  break;
                case '<':
                  if (text[i+1] == '>')
                    {
                      ch = '!';
                      i++;
                    }
                  else if (text[i+1] == '=')
                    {
                      ch = 'L';
                      i++;
                    }
                  else
                    ch = '<';
                  process_operator(ch, op_stack, &stack_top);
                  break;
                case '>':
                  if (text[i+1] == '=')
                    {
                      ch = 'G';
                      i++;
                    }
                  else
                    ch = '>';
                  process_operator(ch, op_stack, &stack_top);
                  break;
               case '(':   // Push
                  lastch = 0;
                  op_stack[stack_top++] = '(';
                  break;
               case ')':
                  lastch = 0;
                  done = process_paren(op_stack, &stack_top);
                  break;
               case '+': case '-':
                  // * * -15
                  if (lastch != 0)
                    {
                          if (lastch == '-' && ch == '-')
                            {
                              if (stack_top > 0) op_stack[stack_top-1] = '+';
                              lastch = '+';
                            }
                          else
                            {
                              if (stack_top > 0) op_stack[stack_top-1] = '-';
                              lastch = '-';
                            }
                    }
                  else
                    {
                      lastch = ch;
                      process_operator(ch, op_stack, &stack_top);
                    }
                  break;
                case '*': case '/': case '^': case '\\':
                  printf("Line %ld: */^ not supported in string expressions\n",line);
                  exit(EXIT_FAILURE);
              }
              /** END SWITCH **/
          }
        else if (ch != 32)
        {
          lastch = 0;
          done = write_string_expression(text, i, op_stack, &stack_top);
          if (done != -1)
            i = done;
        }
        if (done == -1) break;
        i++;
      }
      /** END WHILE **/

  while (stack_top != 0)
    {
      stack_top--;
      ch = op_stack[stack_top];
      if (ch == '(')
        {
          printf("Line %ld: Error in expression, unresolved parenthesis\n",line);
          exit(EXIT_FAILURE);
        }
      else
        {
          write_operator(ch);
        }    
    }
    /** END WHILE **/

    fputc(DT_NONE,fout);
    len_byte_code = len_byte_code + 1;

    return i;
  }
/** END GET_STRING_EXPRESSION **/


int write_expression(char *text, int i, int op_stack[], int *stack_top)
  {
    int n,temp_brace;
    word temp_int;
    char *keyword = (char*)malloc(MAX_TOKEN);

    i = get_token(text, keyword, i);
    //puts(keyword);

    if (isdigit(keyword[0]) != 0 || keyword[0] == '.')
      {
        probe_number(keyword);
        return i-1;
      }
    else if (strcmp("VAL",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_VAL,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_string_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("ASC",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_ASC,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_string_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("INSTR",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_INSTR,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        if (probe_expression(text, i) == DT_EXPRESSION)
          {
            i = get_expression(text,i);
            i = get_token(text, keyword,i);
            expected(",", keyword);
          }
        else
          {
            fputc(DT_NONE,fout);
            len_byte_code++;
          }
        i = get_string_expression(text,i);
        i = get_token(text, keyword,i);
        expected(",", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_string_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("COS",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_COS,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("SIN",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_SIN,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("TAN",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_TAN,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("SQR",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_SQR,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("LOG",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_LOG,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("LOG10",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_LOG10,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("EXP",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_EXP,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("ABS",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_ABS,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("LEN",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_LEN,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_string_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("TIMER",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_TIMER,fout);
        len_byte_code += 3;
        return i-1;
      }
    else if (strcmp("RND",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_RND,fout);
        len_byte_code += 3;        
        get_token(text, keyword,i);
        if (keyword[0] == '(')
          {
            i = get_token(text, keyword,i);
            temp_brace = nobrace;
            nobrace = TRUE;
            i = get_expression(text, i);
            nobrace = temp_brace;
          }
        else
          {
            fputc(DT_NONE,fout);
            len_byte_code++;
            i--;
          }
        return i;
      }
    else if (strcmp("POINT",keyword) == 0)
      {
        num_statements++;
        fputc(DT_FUNCTION,fout);
        fputc(ID_GRAPHICS,fout);
        fputc(IK_POINT,fout);
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        i = get_expression(text, i);     // x
        i = get_token(text,keyword,i);
        expected(",",keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);     // y
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("INT",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_INT,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("FIX",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_FIX,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("CINT",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_CINT,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("CDBL",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_CDBL,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("CSNG",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_CSNG,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("CLNG",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_CLNG,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("LOF",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_LOF,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("LOC",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_LOC,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("EOF",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_EOF,fout);
        len_byte_code += 3;        
        i = get_token(text, keyword,i);
        expected("(", keyword);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("FREEFILE",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_FREEFILE,fout);
        len_byte_code += 3;
        return i-1;
      }
    else if (strcmp("MP3.RUN",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_MM,fout);
        fputc(IK_RUNMP3,fout);
        len_byte_code += 3;
        return i-1;
      }
    else if (strcmp("MP3.BITRATE",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_MM,fout);
        fputc(IK_BITRATEMP3,fout);
        len_byte_code += 3;
        return i-1;
      }
    else if (strcmp("MP3.SAMPRATE",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_MM,fout);
        fputc(IK_SAMPRATEMP3,fout);
        len_byte_code += 3;
        return i-1;
      }
    else if (strcmp("MP3.POLLSIZE",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_MM,fout);
        fputc(IK_POLLSIZEMP3,fout);
        len_byte_code += 3;
        return i-1;
      }
    else if (strcmp("MP3.STEREO",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_MM,fout);
        fputc(IK_STEREOMP3,fout);
        len_byte_code += 3;
        return i-1;
      }
    else if (strcmp("MOD",keyword) == 0)
      {
        process_operator('%', op_stack, stack_top);
        return i-1;
      }
    else if (strcmp("AND",keyword) == 0)
      {
        process_operator('&', op_stack, stack_top);
        return i-1;
      }
    else if (strcmp("OR",keyword) == 0)
      {
        process_operator('|', op_stack, stack_top);
        return i-1;
      }
    else if (strcmp("XOR",keyword) == 0)
      {
        process_operator('X', op_stack, stack_top);
        return i-1;
      }
    else if (strcmp("NOT",keyword) == 0)
      {
        process_operator('~', op_stack, stack_top);
        return i-1;
      }
    else if (strcmp("THEN",keyword) == 0)
     return -1;
    else if (strcmp("TO",keyword) == 0)
     return -1;
    else if (strcmp("STEP",keyword) == 0)
     return -1;

    for (n=0;n<max_intvar;n++)
      {
        if (strcmp(keyword,(intstack+n*4)->name) == 0)
          {
            fputc(DT_VARINT,fout);
            temp_int = n;
            fwrite(&temp_int,2,1,fout);
            len_byte_code = len_byte_code + 3;
            return i-1;
          }
      }
      /** END FOR **/
    for (n=0;n<max_arrintvar;n++)
      {
        if (strcmp(keyword,(arrintstack+n*4)->name) == 0)
          {
            fputc(DT_ARRAY,fout);
            fputc(DT_INTEGER,fout);
            temp_int = n;
            fwrite(&temp_int,2,1,fout);
            len_byte_code = len_byte_code + 4;
            i = get_token(text,keyword,i);
            expected("(",keyword);
            temp_brace = nobrace;
            nobrace = TRUE;
            i = get_expression(text,i);
            nobrace = temp_brace;
            i = get_token(text,keyword,i);
            expected(")",keyword);
            return i-1;
          }
      }
      /** END FOR **/
    for (n=0;n<max_strvar;n++)
      {
        if (strcmp(keyword,(charstack+n*4)->name) == 0)
          {
            fputc(DT_VARSTR,fout);
            temp_int = n;
            fwrite(&temp_int,2,1,fout);
            len_byte_code = len_byte_code + 3;
            return i-1;
          }
      }
      /** END FOR **/

    fputc(DT_FUNCTION,fout);
    len_byte_code++;
    DIM_inplace(keyword);
    i = i - strlen(keyword);

    return i-1;
  }
/** END WRITE_EXPRESSION **/


int write_string_expression(char *text, int i, int op_stack[], int *stack_top)
  {
    int n,max=strlen(text),mid;
    short int temp_brace;
    word temp_int;
    char *keyword = (char*)malloc(MAX_TOKEN);
    char *printtext;
    word len_str;

    i = get_token(text, keyword, i);
    //puts(keyword);

    if (keyword[0] == '"')
      {
        printtext = (char*)malloc(max+1);
        n=i;
        while (i < max && text[i] != '"')
          {
            printtext[i-n] = text[i];   /** Symantec chokes on text[i++] **/
            i++;
          }
        printtext[i-n] = 0;
        fputc(DT_STRING,fout);
        len_str = strlen(printtext);
        fwrite(&len_str,2,1,fout);
        fwrite(printtext,len_str,1,fout);
        len_byte_code = len_byte_code + 3 + len_str;
        //puts(printtext);
        free(printtext);
        return i;
      }
    else if (strcmp("LEFT$",keyword) == 0 || strcmp("RIGHT$",keyword) == 0 || strcmp("MID$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        mid = FALSE;
        if (strcmp("LEFT$",keyword) == 0)
          fputc(IK_LEFT,fout);
        else if (strcmp("RIGHT$",keyword) == 0)
          fputc(IK_RIGHT,fout);
        else
          {
            fputc(IK_MID,fout);
            mid = TRUE;
          }
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        //printf("left$ ");
        i = get_string_expression(text,i);
        i = get_token(text,keyword,i);
        expected(",",keyword);
        temp_brace = nobrace;
        if (mid == FALSE) nobrace = TRUE;
        i = get_expression(text,i);
        if (mid == TRUE)
          {
            //printf("MID$\n");
            i = get_token(text,keyword,i);
            expected(",",keyword);
            nobrace = TRUE;
            i = get_expression(text,i);
          }
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("ENVIRON$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_ENVIRON,fout);
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        temp_brace = nobrace;
        nobrace=TRUE;
        i = get_string_expression(text,i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("LTRIM$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_LTRIM,fout);
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        temp_brace = nobrace;
        nobrace=TRUE;
        i = get_string_expression(text,i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("RTRIM$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_RTRIM,fout);
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        temp_brace = nobrace;
        nobrace=TRUE;
        i = get_string_expression(text,i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("STR$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_STR,fout);
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        temp_brace = nobrace;
        nobrace=TRUE;
        i = get_expression(text,i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("GET$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_GETS,fout);
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        temp_brace = nobrace;
        nobrace=TRUE;
        i = get_expression(text,i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("INKEY$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_DOS,fout);
        fputc(IK_INKEY,fout);
        len_byte_code += 3;
        USE_DOS = TRUE;
        return i-1;
      }
    else if (strcmp("INPUT$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_DOS,fout);
        fputc(IK_INPUT,fout);
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        temp_brace = nobrace;
        nobrace=TRUE;
        i = get_expression(text,i);
        nobrace = temp_brace;
        USE_DOS = TRUE;
        return i;
      }
    else if (strcmp("CHR$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_CHR,fout);
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        temp_brace = nobrace;
        nobrace=TRUE;
        i = get_expression(text,i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("UCASE$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_UCASE,fout);
        i = get_token(text,keyword,i);
        expected("(",keyword);
        len_byte_code += 3;
        temp_brace = nobrace;
        nobrace=TRUE;
        i = get_string_expression(text,i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("LCASE$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_LCASE,fout);
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        temp_brace = nobrace;
        nobrace=TRUE;
        i = get_string_expression(text,i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("TAB",keyword) == 0 || strcmp("SPACE$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_TAB,fout);
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        temp_brace = nobrace;
        nobrace=TRUE;
        i = get_expression(text,i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("STR$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_STR,fout);
        len_byte_code += 3;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        temp_brace = nobrace;
        nobrace=TRUE;
        i = get_expression(text,i);
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("STRING$",keyword) == 0)
      {
        fputc(DT_FUNCTION,fout);
        fputc(ID_ANSI,fout);
        fputc(IK_STRING,fout);
        len_byte_code += 4;
        i = get_token(text,keyword,i);
        expected("(",keyword);
        i = get_expression(text,i);
        i = get_token(text,keyword,i);
        expected(",",keyword);
        temp_brace = nobrace;
        nobrace=TRUE;
        if (probe_expression(text,i) == DT_EXPRESSION)
          {
            fputc(DT_EXPRESSION, fout);
            i = get_expression(text,i);
          }
        else
          {
            fputc(DT_STREXPR, fout);
            i = get_string_expression(text,i);
          }
        nobrace = temp_brace;
        return i;
      }
    else if (strcmp("MOD",keyword) == 0)
      {
        process_operator('%', op_stack, stack_top);
        return i-1;
      }
    else if (strcmp("AND",keyword) == 0)
      {
        process_operator('&', op_stack, stack_top);
        return i-1;
      }
    else if (strcmp("OR",keyword) == 0)
      {
        process_operator('|', op_stack, stack_top);
        return i-1;
      }
    else if (strcmp("XOR",keyword) == 0)
      {
        process_operator('X', op_stack, stack_top);
        return i-1;
      }
    else if (strcmp("NOT",keyword) == 0)
      {
        process_operator('~', op_stack, stack_top);
        return i-1;
      }
    else if (strcmp("THEN",keyword) == 0)
     return -1;
    else if (strcmp("TO",keyword) == 0)
     return -1;
    else if (strcmp("STEP",keyword) == 0)
     return -1;

    for (n=0;n<max_strvar;n++)
      {
        if (strcmp(keyword,(charstack+n*4)->name) == 0)
          {
            fputc(DT_VARSTR,fout);
            temp_int = n;
            fwrite(&temp_int,2,1,fout);
            len_byte_code = len_byte_code + 3;
            return i-1;
          }
      }
      /** END FOR **/
    for (n=0;n<max_arrstrvar;n++)
      {
        if (strcmp(keyword,(arrcharstack+n*4)->name) == 0)
          {
            fputc(DT_ARRAY,fout);
            fputc(DT_STRING,fout);
            temp_int = n;
            fwrite(&temp_int,2,1,fout);
            len_byte_code = len_byte_code + 4;
            i = get_token(text,keyword,i);
            expected("(",keyword);
            temp_brace = nobrace;
            nobrace = TRUE;
            i = get_expression(text,i);
            nobrace = temp_brace;
            i = get_token(text,keyword,i);
            expected(")",keyword);
            return i-1;
          }
      }
      /** END FOR **/

    for (n=0;n<max_intvar;n++)
      {
        if (strcmp(keyword,(intstack+n*4)->name) == 0)
          {
            printf("Line %ld: Numeric variable %s, in string expression!", line, keyword);
            exit(EXIT_FAILURE);
          }
      }
      /** END FOR **/
    for (n=0;n<max_arrintvar;n++)
      {
        if (strcmp(keyword,(arrintstack+n*4)->name) == 0)
          {
            printf("Line %ld: Numeric array variable %s, in string expression!", line, keyword);
            exit(EXIT_FAILURE);
          }
      }
      /** END FOR **/

    fputc(DT_FUNCTION,fout);
    len_byte_code++;
    DIM_inplace(keyword);
    i = i - strlen(keyword);

    return i-1;
  }
/** END WRITE_STRING_EXPRESSION **/


void probe_number(char *num)
  {
    int ch = num[strlen(num)-1];
    byte        byte_num;
    word        word_num;
    dword       dword_num;
    long double ext_num;
    short int   int_num;
    long int    long_num;
    float       float_num;
    double      double_num;

    if (ch == '?')
      {
         if (strlen(num) > 2 && num[strlen(num)-2] == '?')
           {
             if (strlen(num) > 3 && num[strlen(num)-3] == '?')
               {
                 fputc(DT_DWORD,fout);
                 dword_num = atol(num);
                 fwrite(&dword_num,4,1,fout);
                 len_byte_code = len_byte_code + 5;
               }
             else
               {
                 fputc(DT_WORD,fout);
                 word_num = atol(num);
                 fwrite(&word_num,2,1,fout);
                 len_byte_code = len_byte_code + 3;
               }
           }
         else
           {
             fputc(DT_BYTE,fout);
             byte_num = atoi(num);
             fwrite(&byte_num,1,1,fout);
             len_byte_code = len_byte_code + 2;
           }
      }
    else if (ch == '%')
      {
         fputc(DT_INTEGER,fout);
         int_num = atoi(num);
         fwrite(&int_num,2,1,fout);
         len_byte_code = len_byte_code + 3;

      }
    else if (ch == '&')
      {
         fputc(DT_LONGINT,fout);
         long_num = atol(num);
         fwrite(&long_num,4,1,fout);
         len_byte_code = len_byte_code + 5;
      }
    else if (ch == '!')
      {
         fputc(DT_SINGLE,fout);
         float_num = (float)atof(num);
         fwrite(&float_num,4,1,fout);
         len_byte_code = len_byte_code + 5;
      }
    else if (ch == '#')
      {
         if (strlen(num) > 2 && num[strlen(num)-2] == '#')
           {
             fputc(DT_EXT,fout);
             ext_num = atof(num);
             fwrite(&ext_num,10,1,fout);
             len_byte_code = len_byte_code + 11;
           }
         else
           {
             fputc(DT_DOUBLE,fout);
             double_num = atof(num);
             fwrite(&double_num,8,1,fout);
             len_byte_code = len_byte_code + 9;
           }
      }
    else if (ch == '$')
      {
         printf("Line %ld: Invalid string variable %s\n",line,num);
         exit(EXIT_FAILURE);
      }
    else
      {
         if (strchr(num,'.') != NULL)
           {
             fputc(DT_DOUBLE,fout);
             double_num = atof(num);
             fwrite(&double_num,8,1,fout);
             len_byte_code = len_byte_code + 9;
           }
         else
           {
             fputc(DT_LONGINT,fout);
             long_num = atol(num);
             fwrite(&long_num,4,1,fout);
             len_byte_code = len_byte_code + 5;
           }
      }

  }
/** END PROBE_NUMBER **/


int probe_expression(char *text, int i)
  {
    int n,done = FALSE,expression;
    char *keyword = (char*)malloc(MAX_TOKEN);

    do
      {
        i = get_token(text,keyword,i);
      }
    while (keyword[0] == '(');

    if (isdigit(keyword[0]) != 0 || keyword[0] == '+' || keyword[0] == '-' || keyword[0] == '.')
      expression = DT_EXPRESSION;
    else if (strcmp("VAL",keyword) == 0 || strcmp("ASC",keyword) == 0 || strcmp("SQR",keyword) == 0 || strcmp("ABS",keyword) == 0 ||
             strcmp("TAN",keyword) == 0 || strcmp("SIN",keyword) == 0 || strcmp("COS",keyword) == 0 ||
             strcmp("LOG",keyword) == 0 || strcmp("LOG10",keyword) == 0 || strcmp("EXP",keyword) == 0)
      expression = DT_EXPRESSION;
    else if (strcmp("RND",keyword) == 0 || strcmp("TIMER",keyword) == 0 || strcmp("POINT",keyword) == 0)
      expression = DT_EXPRESSION;
    else if (strcmp("INT",keyword) == 0 || strcmp("CINT",keyword) == 0 || strcmp("FIX",keyword) == 0 ||
             strcmp("CSNG",keyword) == 0 || strcmp("CDBL",keyword) == 0  || strcmp("CLNG",keyword) == 0)
      expression = DT_EXPRESSION;
    else if (strcmp("MP3.RUN",keyword) == 0 || strcmp("MP3.BITRATE",keyword) == 0 || strcmp("MP3.SAMPRATE",keyword) == 0 ||
             strcmp("MP3.POLLSIZE",keyword) == 0 || strcmp("MP3.STEREO",keyword) == 0)
      expression = DT_EXPRESSION;
    else if (strcmp("INSTR",keyword) == 0 || strcmp("LEN",keyword) == 0 || strcmp("FREEFILE",keyword) == 0 ||
             strcmp("EOF",keyword) == 0 || strcmp("LOF",keyword) == 0 || strcmp("LOC",keyword) == 0)
      expression = DT_EXPRESSION;
    else if (keyword[0] == '"')
      expression = DT_STREXPR;
    else
      {
        for (n=0;n<max_intvar;n++)
          {
            if (strcmp(keyword,(intstack+4*n)->name) == 0)
              {
                done = TRUE;
                break;
              }
          }
        if (done == FALSE)
          {
            for (n=0;n<max_arrintvar;n++)
            {
              if (strcmp(keyword,(arrintstack+4*n)->name) == 0)
                {
                  done = TRUE;
                  break;
                }
            }
            if (done == FALSE)
              expression = DT_STREXPR;
            else
              expression = DT_EXPRESSION;
          }
        else
          expression = DT_EXPRESSION;
      }

    free(keyword);
    return expression;
  }
/** END PROBE_EXPRESSION **/


char* rtrim(char *text)
  {
     int i;

     if (strlen(text) == 0) return text;

     for (i=strlen(text)-1;i>=0;i--)
       {
         if (text[i]!=' ')
           {
              text[i+1] = 0;
              return text;
           }
       }

     return text;
  }
/** END RTRIM **/


int get_token(char *text, char *token, int n)
  {
    int i=n,x=0;
    int max=strlen(text);
    int ch;
    int first = TRUE;

    while (i < max)
      {
        ch = text[i];
        if (ch == ' ' || ch == '#')
          {
            if (first == FALSE) { i--; break;}
          }
          else
          {
            first = FALSE;
            token[x++] = toupper(ch);
          }
        if (strchr("?();:,=*^+-/<>\"\\",ch) != NULL)
          {
            if (x != 1)
              {
                if (ch != '?')
                  {
                    x--; i--;
                    break;
                  }
              }
            else
              break;
          }
        i++;
      }
      /** END WHILE **/

    token[x] = 0;
    if (i == max)
      return i;
    else
      return (i+1);
  }
/** END GET_TOKEN **/


int read_line(char *text, int n)
  {
    int ch,lastch=0;
    int i = 0;
    int first = TRUE;

    while ((ch = fgetc(fp)) != EOF)
      if (i < n)
        {
           /** Need to support UNIX files as well **/
           if (ch == '\n' || ch == '\r')
             {
               
               if (ch == '\r')
                  if ((ch = fgetc(fp)) != '\n') ungetc(ch, fp);
               if (lastch != '_')
                 break;
               else
                 {
                   line++;
                   i--;
                   text[i] = ' ';
                   first = TRUE;
                 }
             }
           else if (ch == ' ' && first == TRUE)
             {}
           else
             {
                text[i++] = ch;
                lastch = ch;
                first = FALSE;
             }
        }

    if (ch != EOF)
      {
         text[i] = 0;
         text = rtrim(text);
         return i;
      }
    else
      return -1;
  }
/** END READ_LINE **/


void resolve_branches()
  {
    dword cur_addr;
    long int addr,i,j;

    for (i=0;i<max_gotos;i++)
      {
        for (j=0;j<max_labels;j++)
          {
            if (strcmp(gotos[i].caption,labels[j].caption) == 0)
              {
                cur_addr = ftell(fout);
                fseek(fout,gotos[i].address,SEEK_SET);
                addr = labels[j].address - (gotos[i].address + 4);
                fwrite(&addr,4,1,fout);
                fseek(fout,cur_addr,SEEK_SET);
                /**
                if (i == max_gotos-1)
                  {
                    free(gotos[i].caption);
                  }
                else
                  {
                    strcpy(gotos[i].caption,gotos[max_gotos-1].caption);
                    free(gotos[max_gotos-1].caption);
                  }
                i--;
                max_gotos--;
                **/
                break;
              }
          }
      }
  }
/** END RESOLVE BRANCHES **/


int check_strvar(char *variable)
  {
    word i;

    for (i=0;i<max_strvar;i++)
        if (strcmp(variable,(charstack+i*4)->name) == 0) return i;

    return -1;
  }
/** END CHECK_STRVAR **/

int check_strarrvar(char *variable)
  {
    word i;

    for (i=0;i<max_arrstrvar;i++)
        if (strcmp(variable,(arrcharstack+i*4)->name) == 0) return i;

    return -1;
  }
/** END CHECK_STRARRVAR **/

int check_intvar(char *variable)
  {
    word i;

    for (i=0;i<max_intvar;i++)
        if (strcmp(variable,(intstack+i*4)->name) == 0) return i;

    return -1;
  }
/** END CHECK_INTVAR **/

int check_intarrvar(char *variable)
  {
    word i;

    for (i=0;i<max_arrintvar;i++)
        if (strcmp(variable,(arrintstack+i*4)->name) == 0) return i;

    return -1;
  }
/** END CHECK_INTARRVAR **/

void check_dupevar(char *variable)
  {
    word i;

    for (i=0;i<max_strvar;i++)
      {
        if (strcmp(variable,(charstack+i*4)->name) == 0)
          {
            printf("line %ld: Duplicate string variable definition: %s\n",line,variable);
            exit(EXIT_FAILURE);
          }
      }
      /** END FOR **/

    for (i=0;i<max_arrstrvar;i++)
      {
        if (strcmp(variable,(arrcharstack+i*4)->name) == 0)
          {
            printf("line %ld: Duplicate string array definition: %s\n",line,variable);
            exit(EXIT_FAILURE);
          }
      }
      /** END FOR **/

    for (i=0;i<max_intvar;i++)
      {
        if (strcmp(variable,(intstack+i*4)->name) == 0)
          {
            printf("line %ld: Duplicate integer variable definition: %s\n",line,variable);
            exit(EXIT_FAILURE);
          }
      }
      /** END FOR **/

    for (i=0;i<max_arrintvar;i++)
      {
        if (strcmp(variable,(arrintstack+i*4)->name) == 0)
          {
            printf("line %ld: Duplicate integer array definition: %s\n",line,variable);
            exit(EXIT_FAILURE);
          }
      }
      /** END FOR **/
    /*
    if ((labels = search_labels(labels, variable)) != NULL)
      {
        printf("line %ld: Duplicate label definition: %s\n",line,variable);
        exit(EXIT_FAILURE);
      }
    */
  }
/** END CHECK_DUPEVAR **/


int check_and_writeint(char *text, char *token, int i)
/** Check for integer-type variable, then output **/
  {
    word word_num;
    byte byte_num;

    if (check_intvar(token) != -1)
      {
        word_num = check_intvar(token);
        byte_num = (intstack+word_num*4)->type;
        fputc(byte_num,fout);
        fwrite(&word_num,2,1,fout);
        len_byte_code += 3;
      }
    else if(check_intarrvar(token) != -1)
      {
        word_num = check_intarrvar(token);
        fputc(DT_ARRAY,fout);
        fwrite(&word_num,2,1,fout);
        len_byte_code += 3;
            i = get_token(text,token,i);
            expected("(",token);
            nobrace = TRUE;
            i = get_expression(text,i);
            nobrace = FALSE;
            i = get_token(text,token,i);
            expected(")",token);
      }
    else
      {
        fputc(DT_FUNCTION,fout);
        len_byte_code++;
        DIM_inplace(token);
        if (check_intvar(token) != -1)
          {
            word_num = check_intvar(token);
            byte_num = DT_INTEGER;
            fputc(byte_num,fout);
            fwrite(&word_num,2,1,fout);
            len_byte_code += 3;
          }
        else
          {
            printf("Line %ld: Error in SWAP expression, incompatible type for variable %s",line,token);
            exit(EXIT_FAILURE);
          }
      }

    return i;
  }
/** END CHECK_AND_WRITEINT **/


int check_and_writestr(char *text, char *token, int i)
/** Check for a string variable, then output **/
  {
    word word_num;
    byte byte_num;

    if (check_strvar(token) != -1)
      {
        word_num = check_strvar(token);
        fputc(byte_num,fout);
        fwrite(&word_num,2,1,fout);
        len_byte_code += 3;
      }
    else if(check_strarrvar(token) != -1)
      {
        word_num = check_strarrvar(token);
        fputc(DT_ARRAY,fout);
        fwrite(&word_num,2,1,fout);
        len_byte_code += 3;
            i = get_token(text,token,i);
            expected("(",token);
            nobrace = TRUE;
            i = get_expression(text,i);
            nobrace = FALSE;
            i = get_token(text,token,i);
            expected(")",token);
      }
    else
      {
        fputc(DT_FUNCTION,fout);
        len_byte_code++;
        DIM_inplace(token);
        if (check_strvar(token) != -1)
          {
            word_num = check_strvar(token);
            fputc(DT_STRING,fout);
            fwrite(&word_num,2,1,fout);
            len_byte_code += 3;
          }
        else
          {
            printf("Line %ld: Error in SWAP expression, incompatible type for variable %s",line,token);
            exit(EXIT_FAILURE);
          }
      }

    return i;
  }
/** END CHECK_AND_WRITESTR **/


void expected(char *expect, char *text)
  {
    assert(text != NULL);
    if (strcmp(expect,text) != 0)
      {
         printf("line %ld: Expected %s but got \"%s\"",line,expect,text);
         exit(EXIT_FAILURE);
      }
  }
/** END EXPECTED **/


void add_intvar(char *variable, byte datatype)
  {
     if (max_intvar >= int_stack_top)
       {
         int_stack_top+=100;
         realloc(intstack, 4*int_stack_top);
       }
     (intstack+(4*max_intvar))->name = malloc(strlen(variable)+1);

     (intstack+(4*max_intvar))->type = datatype;
     strcpy((intstack+(4*max_intvar++))->name,variable);
  }
/** END ADD_INTVAR **/

void add_arrintvar(char *variable, byte datatype)
  {
     if (max_arrintvar >= arrint_stack_top)
       {
         arrint_stack_top+=100;
         realloc(arrintstack, 4*arrint_stack_top);
       }
     (arrintstack+(4*max_arrintvar))->name = malloc(strlen(variable)+1);

     (arrintstack+(4*max_arrintvar))->type = datatype;
     strcpy((arrintstack+(4*max_arrintvar++))->name,variable);
  }
/** END ADD_ARRINTVAR **/


void add_strvar(char *variable)
  {
     if (max_strvar >= char_stack_top)
       {
         char_stack_top+=100;
         charstack = realloc(charstack, 4*char_stack_top);
       }
     (charstack+(4*max_strvar))->name = malloc(strlen(variable)+1);

     strcpy((charstack+(4*max_strvar++))->name,variable);
  }
/** END ADD_STRVAR **/

void add_arrstrvar(char *variable)
  {
     if (max_arrstrvar >= arrchar_stack_top)
       {
         arrchar_stack_top+=100;
         arrcharstack = realloc(arrcharstack, 4*arrchar_stack_top);
       }
     (arrcharstack+(4*max_arrstrvar))->name = malloc(strlen(variable)+1);

     strcpy((arrcharstack+(4*max_arrstrvar++))->name,variable);
  }
/** END ADD_ARRSTRVAR **/


void DIM_inplace(char *variable)
  {
    int ch = variable[strlen(variable)-1];

    fputc(ID_ANSI,fout);
    fputc(IK_DIM,fout);
    len_byte_code += 2;
    check_dupevar(variable);

    fputs("DIM ",varlst);
    fputs(variable,varlst);
    fputs(" AS ",varlst);

    if (ch == '?')
      {
         if (strlen(variable) > 2 && variable[strlen(variable)-2] == '?')
           {
             if (strlen(variable) > 3 && variable[strlen(variable)-3] == '?')
               {
                 fputc(DT_INTEGER,fout);
                 fwrite(&max_intvar,2,1,fout);
                 len_byte_code += 3;
                 add_intvar(variable, DT_DWORD);
                 fputs("DWORD",varlst);
               }
             else
               {
                 fputc(DT_INTEGER,fout);
                 fwrite(&max_intvar,2,1,fout);
                 len_byte_code += 3;
                 add_intvar(variable, DT_WORD);
                 fputs("WORD",varlst);
               }
           }
         else
           {
             fputc(DT_INTEGER,fout);
             fwrite(&max_intvar,2,1,fout);
             len_byte_code += 3;
             add_intvar(variable, DT_BYTE);
             fputs("BYTE",varlst);
           }
      }
    else if (ch == '%')
      {
         fputc(DT_INTEGER,fout);
         fwrite(&max_intvar,2,1,fout);
         len_byte_code += 3;
         add_intvar(variable, DT_INTEGER);
         fputs("INTEGER",varlst);
      }
    else if (ch == '&')
      {
         fputc(DT_INTEGER,fout);
         fwrite(&max_intvar,2,1,fout);
         len_byte_code += 3;
         add_intvar(variable, DT_LONGINT);
         fputs("LONG",varlst);
      }
    else if (ch == '!')
      {
         fputc(DT_INTEGER,fout);
         fwrite(&max_intvar,2,1,fout);
         len_byte_code += 3;
         add_intvar(variable, DT_SINGLE);
         fputs("SINGLE",varlst);
      }
    else if (ch == '#')
      {
         if (strlen(variable) > 2 && variable[strlen(variable)-2] == '#')
           {
             fputc(DT_INTEGER,fout);
             fwrite(&max_intvar,2,1,fout);
             len_byte_code += 3;
             add_intvar(variable, DT_EXT);
             fputs("EXT",varlst);
           }
         else
           {
             fputc(DT_INTEGER,fout);
             fwrite(&max_intvar,2,1,fout);
             len_byte_code += 3;
             add_intvar(variable, DT_DOUBLE);
             fputs("DOUBLE",varlst);
           }
      }
    else if (ch == '$')
      {
        fputc(DT_STRING,fout);
        fputc(DT_NONE,fout);
        fwrite(&max_strvar,2,1,fout);
        len_byte_code += 4;
        add_strvar(variable);
        fputs("STRING",varlst);
      }
    else
      {
         fputc(DT_INTEGER,fout);
         fwrite(&max_intvar,2,1,fout);
         len_byte_code += 3;
         add_intvar(variable, DT_SINGLE);
         fputs("SINGLE",varlst);
      }
  fputs("\r\n",varlst);

  }
/** END DIM_INPLACE **/


void DIM_footprint(char *text, int *i)
  {
    char *token = (char*)malloc(MAX_TOKEN);
    char *variable = (char*)malloc(MAX_TOKEN);
    int temp_nobrace;

    fputc(ID_ANSI,fout);
    fputc(IK_DIM,fout);
    len_byte_code += 2;
    *i = get_token(text, variable, *i);
    check_dupevar(variable);
    *i = get_token(text, token, *i);
    if (token[0] == '(')
      {
        fputc(DT_ARRAY,fout);
        len_byte_code++;
        temp_nobrace = nobrace;
        nobrace = TRUE;
        *i = get_expression(text, *i);
        nobrace = temp_nobrace;
        *i = get_token(text, token, *i);
        if (strcmp("TO", token) == 0)
          {
            temp_nobrace = nobrace;
            nobrace = TRUE;
            *i = get_expression(text, *i);
            nobrace = temp_nobrace;
            *i = get_token(text, token, *i);
          }
        else
          {
            fputc(DT_NONE,fout);
            len_byte_code++;
          }
        expected(")",token);
        *i = get_token(text, token, *i);
        expected("AS",token);
        *i = get_token(text, token, *i);
        if (strcmp("STRING",token) == 0)
          {
            fputc(DT_STRING,fout);
            *i = get_token(text, token, *i);
            if (token[0] == '*')
              {
                *i = get_expression(text, *i);
                fwrite(&max_arrstrvar,2,1,fout);
                len_byte_code += 3;
              }
            else
              {
                fputc(DT_NONE,fout);
                fwrite(&max_arrstrvar,2,1,fout);
                len_byte_code += 4;
              }
            add_arrstrvar(variable);
          }
        else if (strcmp("INTEGER",token) == 0)
          {
            fputc(DT_INTEGER,fout);
            fwrite(&max_arrintvar,2,1,fout);
            len_byte_code += 3;
            add_arrintvar(variable, DT_INTEGER);
          }
        else if (strcmp("LONG",token) == 0)
          {
            fputc(DT_INTEGER,fout);
            fwrite(&max_arrintvar,2,1,fout);
            len_byte_code += 3;
            add_arrintvar(variable, DT_INTEGER);
          }
        else if (strcmp("DOUBLE",token) == 0)
          {
            fputc(DT_INTEGER,fout);
            fwrite(&max_arrintvar,2,1,fout);
            len_byte_code += 3;
            add_arrintvar(variable, DT_INTEGER);
          }
        else if (strcmp("SINGLE",token) == 0)
          {
            fputc(DT_INTEGER,fout);
            fwrite(&max_arrintvar,2,1,fout);
            len_byte_code += 3;
            add_arrintvar(variable, DT_INTEGER);
          }
        else if (strcmp("WORD",token) == 0)
          {
            fputc(DT_INTEGER,fout);
            fwrite(&max_arrintvar,2,1,fout);
            len_byte_code += 3;
            add_arrintvar(variable, DT_INTEGER);
          }
        else if (strcmp("DWORD",token) == 0)
          {
            fputc(DT_INTEGER,fout);
            fwrite(&max_arrintvar,2,1,fout);
            len_byte_code += 3;
            add_arrintvar(variable, DT_INTEGER);
          }
        else if (strcmp("BYTE",token) == 0)
          {
            fputc(DT_INTEGER,fout);
            fwrite(&max_arrintvar,2,1,fout);
            len_byte_code += 3;
            add_arrintvar(variable, DT_INTEGER);
          }
      }
      /** END IF ARRAY **/
    else
      {
        expected("AS",token);
        *i = get_token(text, token, *i);
        if (strcmp("STRING",token) == 0)
          {
            fputc(DT_STRING,fout);
            *i = get_token(text, token, *i);
            if (token[0] == '*')
              {
                *i = get_expression(text, *i);
                fwrite(&max_strvar,2,1,fout);
                len_byte_code += 3;
              }
            else
              {
                fputc(DT_NONE,fout);
                fwrite(&max_strvar,2,1,fout);
                len_byte_code += 4;
              }
            add_strvar(variable);
          }
        else if (strcmp("BYTE",token) == 0)
      {
        fputc(DT_INTEGER,fout);
        fwrite(&max_intvar,2,1,fout);
        len_byte_code += 3;
        add_intvar(variable, DT_BYTE);
      }
    else if (strcmp("INTEGER",token) == 0)
      {
        fputc(DT_INTEGER,fout);
        fwrite(&max_intvar,2,1,fout);
        len_byte_code += 3;
        add_intvar(variable, DT_INTEGER);
      }
    else if (strcmp("WORD",token) == 0)
      {
        fputc(DT_INTEGER,fout);
        fwrite(&max_intvar,2,1,fout);
        len_byte_code += 3;
        add_intvar(variable, DT_WORD);
      }
    else if (strcmp("DWORD",token) == 0)
      {
        fputc(DT_INTEGER,fout);
        fwrite(&max_intvar,2,1,fout);
        len_byte_code += 3;
        add_intvar(variable, DT_DWORD);
      }
    else if (strcmp("LONG",token) == 0)
      {
        fputc(DT_INTEGER,fout);
        fwrite(&max_intvar,2,1,fout);
        len_byte_code += 3;
        add_intvar(variable, DT_LONGINT);
      }
    else if (strcmp("SINGLE",token) == 0)
      {
        fputc(DT_INTEGER,fout);
        fwrite(&max_intvar,2,1,fout);
        len_byte_code += 3;
        add_intvar(variable,DT_SINGLE);
      }
    else if (strcmp("DOUBLE",token) == 0)
      {
        fputc(DT_INTEGER,fout);
        fwrite(&max_intvar,2,1,fout);
        len_byte_code += 3;
        add_intvar(variable,DT_DOUBLE);
      }
    else if (strcmp("EXT",token) == 0)
      {
        fputc(DT_INTEGER,fout);
        fwrite(&max_intvar,2,1,fout);
        len_byte_code += 3;
        add_intvar(variable,DT_EXT);
      }
    }
    free(token);
    free(variable);
  }
/** END DIM_FOOTPRINT **/


void IF_footprint(char *text, int *i)
  {
    /** DT_NONE
        IK_ELSEIF
        IK_ELSEIF
          DT_NONE    -+
          IK_ELSEIF   |  One block stack, ending with DT_NONE or whatever <> IK_ELSEIF
          ENDIF      -+
        IK_ELSE
        ENDIF
    **/

    char *token = (char*)malloc(MAX_TOKEN);
    dword saved,savedaddress,address;

        fputc(ID_ANSI,fout);
        fputc(IK_IF,fout);
        get_token(text,token,*i);
        if (probe_expression(text,*i) == DT_STREXPR)
          {
            fputc(DT_STREXPR,fout);
            *i = get_string_expression(text, *i);
          }
        else
          {
            fputc(DT_EXPRESSION,fout);
            *i = get_expression(text, *i);
          }
        *i = get_token(text,token, *i);
        expected("THEN",token);
        get_token(text,token, *i);
        if (strlen(token) == 0)
          {  /** Block IF..ENDIF **/
            resolve[resolve_stack].CNTRL_TAG = DT_NONE;    /** Start of condition **/
            //resolve[resolve_stack].CNTRL_TAG = IK_ELSEIF;  /** Easier this way    **/
            resolve[resolve_stack].address = ftell(fout);
            resolve[resolve_stack].gotoaddr = FALSE;  /** Not required here **/
            fwrite(&address,4,1,fout);
            len_byte_code += 7;
            resolve[resolve_stack++].iflbc = len_byte_code;
          }
        else   /** One line **/
          {
            savedaddress = ftell(fout);
            fwrite(&address,4,1,fout);        /** Dummy value **/
            len_byte_code += 7;
            saved = len_byte_code;
            parse_text(text, *i);
            address = ftell(fout);
            fseek(fout, savedaddress, SEEK_SET);
            saved = len_byte_code - saved;
            fwrite(&saved,4,1,fout);          /** Replace dummy value **/
            fseek(fout, address, SEEK_SET);
          }

    free(token);
  }
/** END IF_FOOTPRINT **/


void ELSEIF_footprint(char *text, int *i)
  {
    char *token = (char*)malloc(MAX_TOKEN);
    dword address;

        fputc(ID_ANSI,fout);
        fputc(IK_IF,fout);
        get_token(text,token,*i);
        if (probe_expression(text,*i) == DT_STREXPR)
          {
            fputc(DT_STREXPR,fout);
            *i = get_string_expression(text, *i);
          }
        else
          {
            fputc(DT_EXPRESSION,fout);
            *i = get_expression(text, *i);
          }
        *i = get_token(text,token, *i);
        expected("THEN",token);
        get_token(text,token, *i);
        if (strlen(token) == 0)
          {
            resolve[resolve_stack].address = ftell(fout);
            fwrite(&address,4,1,fout);
            len_byte_code += 7;
            resolve[resolve_stack++].iflbc = len_byte_code;
          }
        else   /** One line **/
          {
            /** error **/
            exit(EXIT_FAILURE);
          }
    free(token);
  }
/** END ELSEIF_FOOTPRINT **/

void print_string_expression(char *text, int *i)
  {
        if (rvalue == FALSE)
          {
            printf("Line %ld: Invalid placement of quotation mark\n",line);
            exit(EXIT_FAILURE);
          }
        fputc(ID_ANSI,fout);
        fputc(IK_PRINT_NOCRLF,fout);
        fputc(DT_STREXPR,fout);
        len_byte_code += 3;
        *i = get_string_expression(text, *i);
        if (text[*i] != ';' && text[*i] != ',')
          {
            fputc(ID_ANSI,fout);
            fputc(IK_PRINT,fout);
            fputc(DT_NONE,fout);
            len_byte_code += 3;
            if (text[*i] == ':')
              {
                rvalue = FALSE;
                parse_text(text, *i+1);
              }
          }
        else
          parse_text(text,*i+1);

  }
/** END PRINT_STRING_EXPRESSION **/


void print_integer_expression(char *text, int *i)
  {
        if (rvalue == FALSE)
          {
            printf("Line %ld: Expected assignment\n",line);
            exit(EXIT_FAILURE);
          }
        else
          {
            fputc(ID_ANSI,fout);
            fputc(IK_PRINT_NOCRLF,fout);
            len_byte_code += 3;
            if (probe_expression(text,*i) == DT_EXPRESSION)
              {
                fputc(DT_EXPRESSION,fout);
                *i = get_expression(text,*i);
              }
            else
              {
                fputc(DT_STREXPR,fout);
                *i = get_string_expression(text,*i);
              }
            if (text[*i] != ';' && text[*i] != ',')
              {
                fputc(ID_ANSI,fout);
                fputc(IK_PRINT,fout);
                fputc(DT_NONE,fout);
                len_byte_code += 3;
                if (text[*i] == ':')
                  {
                    rvalue = FALSE;
                    parse_text(text, *i+1);
                  }
              }
            else
              parse_text(text,*i+1);
          }
  }
/** END PRINT_INTEGER_EXPRESSION **/


int write_variable(char *text, char *token, int i)
  {
     word word_num;
     char *keyword = (char*)malloc(MAX_TOKEN);
     int temp_brace;

        if (check_strvar(token) != -1)
          {
            word_num = check_strvar(token);
            fputc(DT_STRING,fout);
            fwrite(&word_num,2,1,fout);
            len_byte_code += 3;
          }
        else if (check_intvar(token) != -1)
          {
            word_num = check_intvar(token);
            fputc((intstack+word_num*4)->type,fout);
            fwrite(&word_num,2,1,fout);
            len_byte_code += 3;
          }
        else if(check_intarrvar(token) != -1)
          {
            word_num = check_intarrvar(token);
            fputc(DT_ARRAY,fout);
            fputc(DT_INTEGER,fout);
            fwrite(&word_num,2,1,fout);
            len_byte_code += 4;
            i = get_token(text,keyword,i);
            expected("(",keyword);
            temp_brace = nobrace;
            nobrace = TRUE;
            i = get_expression(text,i);
            nobrace = temp_brace;
            i = get_token(text,keyword,i);
            expected(")",keyword);
          }
        else if(check_strarrvar(token) != -1)
          {
            word_num = check_strarrvar(token);
            fputc(DT_ARRAY,fout);
            fputc(DT_STRING,fout);
            fwrite(&word_num,2,1,fout);
            len_byte_code += 4;
            i = get_token(text,keyword,i);
            expected("(",keyword);
            temp_brace = nobrace;
            nobrace = TRUE;
            i = get_expression(text,i);
            nobrace = temp_brace;
            i = get_token(text,keyword,i);
            expected(")",keyword);
          }
        else
          {
            fputc(DT_FUNCTION,fout);
            len_byte_code++;
            DIM_inplace(token);
            i = write_variable(text, token, i);   // Possible infinite loop...
          }

    free(keyword);
    return i;
  }
/** END WRITE_VARIABLE **/


void Read_DATA(char *text, int i)
  {
    int n,max=strlen(text);
    word len_str;
    char *token = (char*)malloc(MAX_TOKEN);
    char *printtext = (char*)malloc(max);

    while (i < max)
      {
        i = get_token(text, token, i);
        if (token[0] == '"')
          {
            n=i;
            while (i < max && text[i] != '"')
              {
                printtext[i-n] = text[i];
                i++;
              }
            printtext[i-n] = 0;
            i++;
            len_str = strlen(printtext);
            fwrite(&len_str,2,1,datafile);
            fwrite(printtext,len_str,1,datafile);
            len_data_seg = len_data_seg + 2 + len_str;
          }
        else if (token[0] == ',')
          {
            // do nothing...
          }
        else
          {
            i = i - strlen(token);
            n=i;
            while (i < max && text[i] != ',')
              {
                printtext[i-n] = text[i];
                i++;
              }
            printtext[i-n] = 0;
            len_str = strlen(printtext);
            fwrite(&len_str,2,1,datafile);
            fwrite(printtext,len_str,1,datafile);
            len_data_seg = len_data_seg + 2 + len_str;
          }
          free(printtext);
          free(token);
      }
      /** END WHILE **/
  }
/** END READ_DATA **/


int parse_text(char *text, int start)
  {
    int i,n,done,temp_brace;
    long int temp_int;
    word word_num;
    short int short_num;
    char *token = (char*)malloc(MAX_TOKEN);
    char *variable = (char*)malloc(MAX_TOKEN);
    dword saved,address;

    i = get_token(text, token, start);
    if (strlen(token) == 0) return 0;     /** end of line **/

    if (token[0] == ':')
      {
        rvalue = FALSE;
        parse_text(text, i);
      }
    else if (token[0] == '\'' || strcmp("REM",token) == 0)
      {
        /** Comment **/
      }
    else if (strcmp("LET",token) == 0)
      {
        parse_text(text, i+1);
      }
    else if (strcmp("DIM",token) == 0)
      {
        //printf("DIM\n");
        num_statements++;
        do
          {
            DIM_footprint(text, &i);
            i = get_token(text, token, i);
          }
        while (token[0] == ',');
        if (token[0] == '\'') i--;
        parse_text(text,i);
      }
      /** END IF DIM **/
    else if (token[0] == '"' || token[0] == ';')
      {
        i = i - strlen(token);
        print_string_expression(text, &i);
      }
    else if (strcmp("LEFT$",token) == 0 || strcmp("RIGHT$",token) == 0 || strcmp("MID$",token) == 0)
      {
        i = i - strlen(token);
        print_string_expression(text, &i);
      }
    else if (strcmp("LTRIM$",token) == 0 || strcmp("RTRIM$",token) == 0 || strcmp("STR$",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_string_expression(text, &i);
      }
    else if (strcmp("GET$",token) == 0 || strcmp("CHR$",token) == 0 || strcmp("STRING$",token) == 0 || strcmp("STR$",token) == 0 || strcmp("ENVIRON$",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_string_expression(text, &i);
      }
    else if (strcmp("UCASE$",token) == 0 || strcmp("LCASE$",token) == 0 || strcmp("TAB",token) == 0 || strcmp("SPACE$",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_string_expression(text, &i);
      }
    else if (strcmp("INPUT$",token) == 0)
      {
        //printf("INPUT$\n");
        num_statements++;
        i = i - strlen(token);
        print_string_expression(text, &i);
        USE_DOS = TRUE;
      }
    else if (rvalue == TRUE && (isdigit(token[0]) != 0 || token[0] == '(' || token[0] == '-' || token[0] == '+' || token[0] == '.'))
      {
        //printf("integer expression\n");
        if (text[i-1] == ' ') i--;
        i = i - strlen(token);
        print_integer_expression(text, &i);
      }
      /** END IF INTEGER EXPRESSION **/
    else if (strcmp("VAL",token) == 0 || strcmp("ASC",token) == 0 || strcmp("SQR",token) == 0 || strcmp("ABS",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_integer_expression(text, &i);
      }
    else if (strcmp("TAN",token) == 0 || strcmp("SIN",token) == 0 || strcmp("COS",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_integer_expression(text, &i);
      }
    else if (strcmp("LOG",token) == 0 || strcmp("LOG10",token) == 0 || strcmp("EXP",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_integer_expression(text, &i);
      }
    else if (strcmp("RND",token) == 0 || strcmp("TIMER",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_integer_expression(text, &i);
      }
    else if (strcmp("POINT",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_integer_expression(text, &i);
      }
    else if (strcmp("INT",token) == 0 || strcmp("CINT",token) == 0 || strcmp("FIX",token) == 0 ||
             strcmp("CSNG",token) == 0 || strcmp("CDBL",token) == 0  || strcmp("CLNG",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_integer_expression(text, &i);
      }
    else if (strcmp("MP3.RUN",token) == 0 || strcmp("MP3.BITRATE",token) == 0 || strcmp("MP3.SAMPRATE",token) == 0 ||
             strcmp("MP3.POLLSIZE",token) == 0 || strcmp("MP3.STEREO",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_integer_expression(text, &i);
      }
    else if (strcmp("INKEY$",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_string_expression(text, &i);
        USE_DOS = TRUE;
      }
    else if (strcmp("INSTR",token) == 0 || strcmp("LEN",token) == 0 || strcmp("FREEFILE",token) == 0 ||
             strcmp("EOF",token) == 0 || strcmp("LOF",token) == 0 || strcmp("LOC",token) == 0)
      {
        num_statements++;
        i = i - strlen(token);
        print_integer_expression(text, &i);
      }
    else if (strcmp("INPUT",token) == 0)
      {
        //printf("INPUT STRING\n");
        num_statements++;
        get_token(text,token,i);
        if (token[0] == '"')
          {
            fputc(ID_ANSI,fout);
            fputc(IK_PRINT_NOCRLF,fout);
            fputc(DT_STREXPR,fout);
            len_byte_code += 3;
            i = get_string_expression(text,i);
            i = get_token(text,token,i);
            if (token[0] == ';')
              {
                fputc(ID_ANSI,fout);
                fputc(IK_PRINT_NOCRLF,fout);
                fputc(DT_STREXPR,fout);
                fputc(DT_STRING,fout);
                word_num = 2;
                fwrite(&word_num,2,1,fout);
                fputc('?',fout);
                fputc(' ',fout);
                fputc(DT_NONE,fout);
                len_byte_code += 9;
              }
            else if (token[0] != ',')
              {
                printf("Line %ld: Error in INPUT, expected [;|,]",line);
                exit(EXIT_FAILURE);
              }
          }
          /** END IF **/
        fputc(ID_ANSI,fout);
        fputc(IK_INPUTSTR,fout);
        len_byte_code += 2;
        i = get_token(text,token,i);

        if (check_strvar(token) != -1)
          {
            word_num = check_strvar(token);
            fputc(DT_STRING,fout);
            fwrite(&word_num,2,1,fout);
            len_byte_code += 3;
          }
        else if (check_intvar(token) != -1)
          {
            word_num = check_intvar(token);
            fputc((intstack+word_num*4)->type,fout);
            fwrite(&word_num,2,1,fout);
            len_byte_code += 3;
          }
        else
          {
            fputc(DT_FUNCTION,fout);
            len_byte_code++;
            DIM_inplace(token);
            if (check_strvar(token) != -1)
              {
                word_num = check_strvar(token);
                fputc(DT_STRING,fout);
                fwrite(&word_num,2,1,fout);
                len_byte_code += 3;
              }
            else if (check_intvar(token) != -1)
              {
                word_num = check_intvar(token);
                fputc((intstack+word_num*4)->type,fout);
                fwrite(&word_num,2,1,fout);
                len_byte_code += 3;
              }
            else
              {
                printf("Line %ld: INPUT restricted to string or integers, no arrays yet...",line);
                exit(EXIT_FAILURE);
              }
          }
      }
      /** END IF INPUT STRING **/
    else if (strcmp("CONST",token) == 0)
      {
        parse_text(text,i);
      }
    else if (strcmp("PRINT",token) == 0 || strcmp("?",token) == 0)
      {
        //printf("PRINT\n");
        num_statements++;
        get_token(text,token,i);
        if (strlen(token) == 0 || token[0] == ':')
          {
            fputc(ID_ANSI,fout);
            fputc(IK_PRINT,fout);
            fputc(DT_NONE,fout);
            len_byte_code += 3;
            if (token[0] == ':')
              {
                rvalue = FALSE;
                parse_text(text, i+1);
              }
          }
        else
          {
            rvalue = TRUE;
            parse_text(text,i);
            rvalue = FALSE;
          }
      }
      /** END IF PRINT **/
    else if (strcmp("SWAP",token) == 0)
      {
        //printf("SWAP\n");
        num_statements++;
        fputc(ID_ANSI,fout);
        fputc(IK_SWAP,fout);
        len_byte_code += 2;
        if (probe_expression(text, i) == DT_EXPRESSION)
          {
            i = get_token(text,token,i);
            if (check_intarrvar(token) != -1)
              {
                fputc(DT_ARRAY,fout);
                fputc(DT_INTEGER,fout);
                len_byte_code += 2;
              }
            else
              {
                fputc(DT_EXPRESSION,fout);
                len_byte_code++;
              }
            i = check_and_writeint(text, token, i);
            i = get_token(text,token,i);
            if (token[0] == ',')
              {
                i = get_token(text,token,i);
                i = check_and_writeint(text,token,i);
              }
            else
              {
                printf("Line %ld: Missing comma ',' in SWAP expression\n",line);
                exit(EXIT_FAILURE);
              }
          }
        else
          {
            i = get_token(text,token,i);
            if (check_strarrvar(token) != -1)
              {
                fputc(DT_ARRAY,fout);
                fputc(DT_STRING,fout);
                len_byte_code += 2;
              }
            else
              {
                fputc(DT_STREXPR,fout);
                len_byte_code++;
              }
            i = check_and_writestr(text,token,i);
            i = get_token(text,token,i);
            if (token[0] == ',')
              {
                i = get_token(text,token,i);
                i = check_and_writestr(text,token,i);
              }
            else
              {
                printf("Line %ld: Missing comma ',' in SWAP expression\n",line);
                exit(EXIT_FAILURE);
              }
          }
        parse_text(text,i);
      }
      /** END IF SWAP **/
    else if (strcmp("LOCATE",token) == 0)
      {
        //printf("LOCATE\n");
        num_statements++;
        fputc(ID_DOS,fout);
        fputc(IK_LOCATE,fout);
        len_byte_code += 2;
        i = get_expression(text,i);
        i = get_token(text,token,i);
        if (token[0] == ',')
          {
            i = get_expression(text,i);
            i = get_token(text,token,i);
            if (token[0] == ',')
              {
                i = get_expression(text,i);
              }
            else
              {
                fputc(DT_INTEGER,fout);
                short_num = -1;
                fwrite(&short_num,2,1,fout);
                fputc(DT_NONE,fout);
                len_byte_code += 4;
              }
          }
        else
          {
            fputc(DT_NONE,fout);
            fputc(DT_INTEGER,fout);
            short_num = -1;
            fwrite(&short_num,2,1,fout);
            fputc(DT_NONE,fout);
            len_byte_code += 5;
          }
        USE_DOS = TRUE;
        parse_text(text,i);
      }
    else if (strcmp("COLOR",token) == 0)
      {
        //printf("COLOR\n");
        num_statements++;
        fputc(ID_DOS,fout);
        fputc(IK_COLOR,fout);
        len_byte_code += 2;
        get_token(text,token,i);
        if (token[0] == ',')
          {
            fputc(DT_INTEGER,fout);
            short_num = -1;
            fwrite(&short_num,2,1,fout);
            fputc(DT_NONE,fout);
            len_byte_code += 4;
          }
        else
          i = get_expression(text,i);
        i = get_token(text,token,i);
        if (token[0] == ',')
          {
            i = get_expression(text,i);
          }
        else
          {
            fputc(DT_INTEGER,fout);
            short_num = -1;
            fwrite(&short_num,2,1,fout);
            fputc(DT_NONE,fout);
            len_byte_code += 4;
          }
        USE_DOS = TRUE;
        parse_text(text,i);
      }
    else if (strcmp("OPEN",token) == 0)
      {
        //printf("OPEN\n");
        num_statements++;
        fputc(ID_ANSI,fout);
        fputc(IK_OPEN,fout);
        len_byte_code += 2;
        i = get_string_expression(text, i);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_expression(text,i);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_string_expression(text, i);
        parse_text(text,i);
      }
    else if (strcmp("GET",token) == 0)
      {
        num_statements++;
        fputc(ID_ANSI,fout);
        fputc(IK_GET,fout);
        len_byte_code += 2;
        i = get_expression(text, i);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_expression(text,i);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_token(text,token,i);
        write_variable(text,token,i);
        parse_text(text,i);
      }
    else if (strcmp("PUT",token) == 0)
      {
        num_statements++;
        fputc(ID_ANSI,fout);
        fputc(IK_PUT,fout);
        len_byte_code += 2;
        i = get_expression(text, i);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_expression(text,i);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_token(text,token,i);
        write_variable(text,token,i);
        parse_text(text,i);
      }
    else if (strcmp("SEEK",token) == 0)
      {
        num_statements++;
        fputc(ID_ANSI,fout);
        fputc(IK_SEEK,fout);
        len_byte_code += 2;
        i = get_expression(text, i);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_expression(text,i);
        parse_text(text,i);
      }
    else if (strcmp("CLOSE",token) == 0)
      {
        num_statements++;
        do
          {
            fputc(ID_ANSI,fout);
            fputc(IK_CLOSE,fout);
            len_byte_code += 2;
            i = get_expression(text,i);
            i = get_token(text, token, i);
          }
          while (token[0] == ',');
        parse_text(text,i);
      }
    else if (strcmp("KILL",token) == 0)
      {
        num_statements++;
        fputc(ID_ANSI,fout);
        fputc(IK_KILL,fout);
        len_byte_code += 2;
        i = get_string_expression(text, i);
        parse_text(text,i);
      }
    else if (strcmp("MP3.POLL",token) == 0)
      {
        num_statements++;
        fputc(ID_MM,fout);
        fputc(IK_POLLMP3,fout);
        len_byte_code += 2;
        return i-1;
      }
    else if (strcmp("RANDOMIZE",token) == 0)
      {
        //printf("RANDOMIZE\n");
        num_statements++;
        fputc(ID_ANSI,fout);
        fputc(IK_RANDOMIZE,fout);
        len_byte_code += 2;
        get_token(text,token,i);
        if (strcmp("TIMER",token) == 0)
          i = get_token(text,token,i);
        parse_text(text,i);
      }
    else if (strcmp("SLEEP",token) == 0)
      {
        //printf("SLEEP\n");
        num_statements++;
        fputc(ID_ANSI,fout);
        fputc(IK_SLEEP,fout);
        len_byte_code += 2;
        i = get_expression(text, i);
        parse_text(text,i);
      }
    else if (strcmp("GOTO",token) == 0)
      {
        //printf("GOTO\n");
        fputc(ID_ANSI,fout);
        fputc(IK_GOTO,fout);
        i = get_token(text,token,i);
        add_gotos(token, ftell(fout));
        fwrite(&i,4,1,fout);   /** This will be replaced **/
        len_byte_code += 6;
        resolve_branches();
        parse_text(text,i);
      }
    else if (strcmp("GOSUB",token) == 0)
      {
        //printf("GOSUB\n");
        fputc(ID_ANSI,fout);
        fputc(IK_GOSUB,fout);
        i = get_token(text,token,i);
        add_gotos(token, ftell(fout));
        fwrite(&i,4,1,fout);
        len_byte_code += 6;
        resolve_branches();
        parse_text(text,i);
      }
    else if (strcmp("RETURN",token) == 0)
      {
        // printf("RETURN\n");
        fputc(ID_ANSI,fout);
        fputc(IK_RETURN,fout);
        len_byte_code += 2;
        parse_text(text,i);
      }
    else if (strcmp("DATA",token) == 0)
      {
        Read_DATA(text, i);
      }
    else if (strcmp("READ",token) == 0)
      {
        do
          {
            fputc(ID_ANSI,fout);
            fputc(IK_READ,fout);
            len_byte_code += 2;
            i = get_token(text, token, i);
            i = write_variable(text, token, i);
            i = get_token(text, token, i);
          }
          while (token[0] == ',');
        parse_text(text, i);
      }
    else if (strcmp("RESTORE",token) == 0)
      {
        fputc(ID_ANSI,fout);
        fputc(IK_RESTORE,fout);
        len_byte_code += 2;
        parse_text(text, i);
      }
    else if (strcmp("IF",token) == 0)
      {
        //printf("IF\n");
        num_statements++;
        IF_footprint(text, &i);
      }
      /** END IF IF **/
    else if (strcmp("ELSEIF",token) == 0)
      {
        if (resolve_stack == 0 || (resolve[resolve_stack-1].CNTRL_TAG != DT_NONE && resolve[resolve_stack-1].CNTRL_TAG != IK_ELSEIF))
          {
            printf("Line %ld: ELSE without block IF\n",line);
            exit(EXIT_FAILURE);
          }
        else
          {
              /** First, setup GOTO **/
            fputc(ID_ANSI,fout);        /** This will jump to END IF **/
            fputc(IK_GOTO,fout);
            fwrite(&address,4,1,fout);  /** Dummy value **/
            len_byte_code += 6;
              /** Next, resolve IF false **/
            address = ftell(fout);
              /** Jump to this address when IF returns false **/
              /** Will point to next ELSEIF condition        **/
            resolve_stack--;
            fseek(fout, resolve[resolve_stack].address, SEEK_SET);
            saved = len_byte_code - resolve[resolve_stack].iflbc;
            fwrite(&saved,4,1,fout);
            fseek(fout, address, SEEK_SET);
            resolve_stack++;
            resolve[resolve_stack].lbc = len_byte_code;
            resolve[resolve_stack].gotoaddr = len_byte_code-4;
            resolve[resolve_stack].CNTRL_TAG = IK_ELSEIF;
            ELSEIF_footprint(text,&i);
          }
      }
      /** END IF ELSEIF **/
    else if (strcmp("ELSE",token) == 0)
      {
        if (resolve_stack == 0 || (resolve[resolve_stack-1].CNTRL_TAG != DT_NONE && resolve[resolve_stack-1].CNTRL_TAG != IK_ELSEIF))
          {
            printf("Line %ld: ELSE without block IF\n",line);
            exit(EXIT_FAILURE);
          }
        else
          {
              /** First, setup GOTO **/
            fputc(ID_ANSI,fout);        /** This will jump to END IF **/
            fputc(IK_GOTO,fout);
            fwrite(&address,4,1,fout);  /** Dummy value **/
            len_byte_code += 6;
              /** Next, resolve IF false **/
            address = ftell(fout);
              /** Jump to this address when IF returns false **/
              /** Will point to next ELSEIF condition        **/
            resolve_stack--;
            fseek(fout, resolve[resolve_stack].address, SEEK_SET);
            saved = len_byte_code - resolve[resolve_stack].iflbc;
            fwrite(&saved,4,1,fout);
            fseek(fout, address, SEEK_SET);
            resolve_stack++;
            resolve[resolve_stack].lbc = len_byte_code;
            resolve[resolve_stack].gotoaddr = len_byte_code-4;
            resolve[resolve_stack++].CNTRL_TAG = IK_ELSE;
          }
      }
      /** END IF ELSE **/
    else if (strcmp("END",token) == 0)
      {
        i = get_token(text, token, i);
        if (strcmp("IF",token) != 0)
          {
            num_statements++;
            fputc(255,fout);
            len_byte_code += 1;
          }
        else
          {
            if (resolve_stack != 0 && (resolve[resolve_stack-1].CNTRL_TAG == DT_NONE || resolve[resolve_stack-1].CNTRL_TAG == IK_ELSEIF || resolve[resolve_stack-1].CNTRL_TAG == IK_ELSE))
              {
                /** Resolve IF false, but ELSE has not IF block **/
                resolve_stack--;
                if (resolve[resolve_stack].CNTRL_TAG != IK_ELSE)
                  {
                    address = ftell(fout);
                    fseek(fout, resolve[resolve_stack].address, SEEK_SET);
                    saved = len_byte_code - resolve[resolve_stack].iflbc;
                    fwrite(&saved,4,1,fout);
                    fseek(fout, address, SEEK_SET);
                  }
                /** Resolve all GOTOs **/
                if (resolve[resolve_stack].CNTRL_TAG != DT_NONE)
                  {
                    do
                      {
                        address = ftell(fout);
                        fseek(fout, resolve[resolve_stack].gotoaddr, SEEK_SET);
                        saved = len_byte_code - resolve[resolve_stack].lbc;
                        fwrite(&saved,4,1,fout);
                        fseek(fout, address, SEEK_SET);
                        resolve_stack--;
                      }
                    while (resolve_stack > 0 && resolve[resolve_stack].CNTRL_TAG != DT_NONE);
                  }
              }
            else
              {
                 printf("Line %ld: END IF without block IF\n",line);
                 printf("Stack: %d\n",resolve_stack);
                 exit(EXIT_FAILURE);
              }
          }
          /** END ELSE **/
        parse_text(text,i);
      }
      /** END END STATEMENT **/
    else if (strcmp("WHILE",token) == 0)
      {
        //printf("WHILE\n");
        num_statements++;
        resolve[resolve_stack].CNTRL_TAG = IK_WHILE;
        resolve[resolve_stack].gotoaddr = ftell(fout);
        fputc(ID_ANSI,fout);
        fputc(IK_IF,fout);
        if (probe_expression(text,i) == DT_STREXPR)
          {
            fputc(DT_STREXPR,fout);
            i = get_string_expression(text, i);
          }
        else
          {
            fputc(DT_EXPRESSION,fout);
            i = get_expression(text, i);
          }
        resolve[resolve_stack].address = ftell(fout);
        fwrite(&address,4,1,fout);
        len_byte_code += 7;
        resolve[resolve_stack++].lbc = len_byte_code;
        parse_text(text,i);
      }
    else if (strcmp("WEND",token) == 0)
      {
        if (resolve_stack == 0 || resolve[resolve_stack-1].CNTRL_TAG != IK_WHILE)
          {
            printf("Line %ld: WEND without block WHILE\n",line);
            printf("stack: %d\n",resolve_stack);
            exit(EXIT_FAILURE);
          }
        else
          {
            resolve_stack--;
            fputc(ID_ANSI,fout);
            fputc(IK_GOTO,fout);
            len_byte_code += 6;
            address = resolve[resolve_stack].gotoaddr - len_byte_code;
            fwrite(&address,4,1,fout);
            address = ftell(fout);
            fseek(fout, resolve[resolve_stack].address, SEEK_SET);
            saved = len_byte_code - resolve[resolve_stack].lbc;
            fwrite(&saved,4,1,fout);
            fseek(fout, address, SEEK_SET);
          }
        parse_text(text,i);
      }
    else if (strcmp("DO",token) == 0)
      {
        //printf("DO\n");
        num_statements++;
        resolve[resolve_stack].CNTRL_TAG = IK_DO;
        resolve[resolve_stack++].gotoaddr = ftell(fout);
        parse_text(text,i);
      }
      /** END IF DO **/
    else if (strcmp("LOOP",token) == 0)
      {
        if (resolve_stack == 0 || resolve[resolve_stack-1].CNTRL_TAG != IK_DO)
          {
            printf("Line %ld: LOOP without block DO\n",line);
            printf("stack: %d\n",resolve_stack);
            exit(EXIT_FAILURE);
          }
        else
          {
            i = get_token(text,token,i);
            if (strlen(token) == 0)
              {
                fputc(ID_ANSI,fout);
                fputc(IK_GOTO,fout);
                len_byte_code += 6;
                resolve_stack--;
                  /** go back to DO **/
                address = resolve[resolve_stack].gotoaddr - len_byte_code;
                fwrite(&address,4,1,fout);
              }
            else
              {
                expected("UNTIL",token);
                fputc(ID_ANSI,fout);
                fputc(IK_IF,fout);
                if (probe_expression(text,i) == DT_STREXPR)
                  {
                    fputc(DT_STREXPR,fout);
                    i = get_string_expression(text, i);
                  }
                else
                  {
                    fputc(DT_EXPRESSION,fout);
                    i = get_expression(text, i);
                  }
                len_byte_code += 7;
                resolve_stack--;
                  /** go back to DO if false **/
                address = resolve[resolve_stack].gotoaddr - len_byte_code;
                fwrite(&address,4,1,fout);
              }
          }
        parse_text(text,i);
      }
      /** END IF LOOP **/
    else if (strcmp("FOR",token) == 0)
      {
        // A FOR statement is simply an IF statement repeated
        //printf("FOR\n");
        num_statements++;
        i = get_token(text,token,i);
        done = FALSE;
          for (n=0;n<max_intvar;n++)
            {
              if (strcmp(token,(intstack+4*n)->name) == 0)
                {
                  done = TRUE;
                  break;
                }
            }
            /** END FOR **/
        if (done == FALSE)
          {
            DIM_inplace(token);
            for (n=0;n<max_intvar;n++)
              {
               if (strcmp(token,(intstack+4*n)->name) == 0)
                  {
                    done = TRUE;
                    break;
                  }
              }
            if (done == FALSE)
              {
                printf("Line %ld: Variable %s, must be an integer!", line, token);
                exit(EXIT_FAILURE);
              }
          }
                  i = get_token(text, token, i);
                  expected("=",token);
                  fputc(ID_VARIABLE,fout);
                  fputc(IK_ASSIGNMENT,fout);
                  fputc(DT_DOUBLE,fout);
                  word_num = n;
                  fwrite(&word_num,2,1,fout);
                  i = get_expression(text, i);
                  fputc(ID_ANSI,fout);
                  fputc(IK_STEP,fout);
                  //depend_addr[depend_stack++] = ftell(fout);
                  saved = ftell(fout);
                  fputc(DT_NONE,fout);
                  fwrite(&word_num,2,1,fout);
                  len_byte_code += 10;

        resolve[resolve_stack].CNTRL_TAG = IK_FOR;
        resolve[resolve_stack].gotoaddr = len_byte_code;
        resolve[resolve_stack].var = word_num;
        i = get_token(text, token, i);
        expected("TO",token);
        fputc(ID_ANSI,fout);
        fputc(IK_IF,fout);
        fputc(DT_EXPRESSION,fout);
        fputc(DT_VARINT,fout);       // Confusing, yep!
        fwrite(&word_num,2,1,fout);
        i = get_expression(text, i);
        resolve[resolve_stack].step = 1;
        resolve[resolve_stack].step_var = FALSE;
        i = get_token(text, token, i);
        if (strcmp("STEP",token) == 0)
          {
            i = get_token(text,token,i);
            if (isdigit(token[0]) != 0 || token[0] == '-')
              {
                if (token[0] == '-')
                  {
                    i = get_token(text,token,i);
                    resolve[resolve_stack].step = -atoi(token);
                  }
                else
                  resolve[resolve_stack].step = atoi(token);
              }
            else
              {
                for (n=0;n<max_intvar;n++)
                  {
                    if (strcmp(token,(intstack+4*n)->name) == 0)
                      {
                        resolve[resolve_stack].step = n;
                        resolve[resolve_stack].step_var = TRUE;
                        done = TRUE;
                        break;
                      }
                  }
                  /** END FOR **/
                if (done == FALSE)
                  {
                    printf("Line %ld: Unknown variable name: %s", line, token);
                    exit(EXIT_FAILURE);
                  }
              }
              /** END ELSE **/
          }
          /** END IF **/
        address = ftell(fout);
        fseek(fout,saved,SEEK_SET);
        if (resolve[resolve_stack].step_var == TRUE)
          {
            fputc(DT_VARINT,fout);
          }
        else
          {
            fputc(DT_INTEGER,fout);
          }
        fwrite(&resolve[resolve_stack].step,2,1,fout);
        fseek(fout,address,SEEK_SET);
        fseek(fout,-1,SEEK_CUR);     // Remove DT_NONE from expression
        fputc(EX_DEPEND,fout);       // Add the comparison.
        fputc(DT_NONE,fout);
        len_byte_code += 11;
        resolve[resolve_stack].address = ftell(fout);
        resolve[resolve_stack++].lbc = len_byte_code;
        fwrite(&address,4,1,fout);
        parse_text(text, i);
      }
      /** END IF FOR **/
    else if (strcmp("NEXT",token) == 0)
      {
        if (resolve_stack == 0 || resolve[resolve_stack-1].CNTRL_TAG != IK_FOR)
          {
            printf("Line %ld: NEXT without block FOR\n",line);
            exit(EXIT_FAILURE);
          }
        resolve_stack--;
        // Increment variable by step (omitted = 1)
        fputc(ID_VARIABLE,fout);
        fputc(IK_ASSIGNMENT,fout);
        fputc(DT_DOUBLE,fout);
        word_num = resolve[resolve_stack].var;
        fwrite(&word_num,2,1,fout);
        fputc(DT_VARINT,fout);
        fwrite(&word_num,2,1,fout);
        if (resolve[resolve_stack].step_var == FALSE)
           fputc(DT_INTEGER,fout);
        else
           fputc(DT_VARINT,fout);
        short_num = resolve[resolve_stack].step;
        fwrite(&short_num,2,1,fout);
        fputc(OP_ADD,fout);
        fputc(DT_NONE,fout);
        len_byte_code += 13;
        fputc(ID_ANSI,fout);
        fputc(IK_GOTO,fout);
        len_byte_code += 6;
        address = resolve[resolve_stack].gotoaddr - (len_byte_code);
        fwrite(&address,4,1,fout);
        address = ftell(fout);
        fseek(fout, resolve[resolve_stack].address, SEEK_SET);
        saved = len_byte_code - resolve[resolve_stack].lbc;
        fwrite(&saved,4,1,fout);
        fseek(fout, address, SEEK_SET);
        i = get_token(text, token, i);
        parse_text(text, i);
      }
      /** END IF NEXT **/
    else if (strcmp("CLS",token) == 0)
      {
        num_statements++;
        fputc(ID_DOS,fout);
        fputc(IK_CLS,fout);
        len_byte_code = len_byte_code + 2;
        USE_DOS = TRUE;
        parse_text(text,i);
      }
    else if (strcmp("SCREEN",token) == 0)
      {
        num_statements++;
        fputc(ID_GRAPHICS,fout);
        fputc(IK_SCREEN,fout);
        len_byte_code += 2;
        i = get_expression(text, i);
        USE_GRAPHICS = TRUE;
        parse_text(text,i);
      }
    else if (strcmp("LINE",token) == 0)
      {
        num_statements++;
        fputc(ID_GRAPHICS,fout);
        saved = ftell(fout);
        fputc(IK_LINE,fout);
        len_byte_code += 2;
        i = get_token(text,token,i);
        expected("(",token);
        i = get_expression(text, i);     // x1
        i = get_token(text,token,i);
        expected(",",token);
        nobrace = TRUE;
        i = get_expression(text, i);     // y1
        nobrace = FALSE;
        i = get_token(text,token,i);
        expected(")",token);
        i = get_token(text,token,i);
        expected("-",token);
        i = get_token(text,token,i);
        expected("(",token);
        i = get_expression(text, i);     // x2
        i = get_token(text,token,i);
        expected(",",token);
        nobrace = TRUE;
        i = get_expression(text, i);     // y2
        nobrace = FALSE;
        i = get_token(text,token,i);
        expected(")",token);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_expression(text, i);     // color
        i = get_token(text,token,i);
        if (token[0] == ',')
          {
             i = get_token(text,token,i);
             if (strcmp("B",token) == 0)
               {
                 fseek(fout,saved,SEEK_SET);
                 fputc(IK_RECT,fout);
                 fseek(fout,0,SEEK_END);
               }
             else if (strcmp("BF",token) == 0)
               {
                 fseek(fout,saved,SEEK_SET);
                 fputc(IK_RECTFILL,fout);
                 fseek(fout,0,SEEK_END);
               }
             else
               {
                  printf("Line %ld: Error in LINE statement, expected B or BF, but got %s",line,token);
                  exit(EXIT_FAILURE);
               }
          }
        USE_GRAPHICS = TRUE;
        parse_text(text,i);
      }
    else if (strcmp("CIRCLE",token) == 0)
      {
        num_statements++;
        fputc(ID_GRAPHICS,fout);
        fputc(IK_CIRCLE,fout);
        len_byte_code += 2;
        i = get_token(text,token,i);
        expected("(",token);
        i = get_expression(text, i);     // x
        i = get_token(text,token,i);
        expected(",",token);
        nobrace = TRUE;
        i = get_expression(text, i);     // y
        nobrace = FALSE;
        i = get_token(text,token,i);
        expected(")",token);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_expression(text, i);     // radius
        i = get_token(text,token,i);
        expected(",",token);
        i = get_expression(text, i);     // color
        parse_text(text,i);
      }
    else if (strcmp("PAINT",token) == 0)
      {
        num_statements++;
        fputc(ID_GRAPHICS,fout);
        fputc(IK_PAINT,fout);
        len_byte_code += 2;
        i = get_token(text,token,i);
        expected("(",token);
        i = get_expression(text, i);     // x
        i = get_token(text,token,i);
        expected(",",token);
        nobrace = TRUE;
        i = get_expression(text, i);     // y
        nobrace = FALSE;
        i = get_token(text,token,i);
        expected(")",token);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_expression(text, i);     // color
        i = get_token(text,token,i);
        if (token[0] == ',')
          {
            i = get_expression(text, i);     // optional
          }
        else
          {
            fputc(DT_NONE,fout);
            len_byte_code++;
          }
        parse_text(text,i);
      }
    else if (strcmp("PSET",token) == 0)
      {
        num_statements++;
        fputc(ID_GRAPHICS,fout);
        fputc(IK_PSET,fout);
        len_byte_code += 2;
        i = get_token(text,token,i);
        expected("(",token);
        i = get_expression(text, i);     // x
        i = get_token(text,token,i);
        expected(",",token);
        nobrace = TRUE;
        i = get_expression(text, i);     // y
        nobrace = FALSE;
        i = get_token(text,token,i);
        expected(")",token);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_expression(text, i);     // color
        parse_text(text,i);
      }
    else if (strcmp("SHOWJPG",token) == 0)
      {
        num_statements++;
        fputc(ID_GRAPHICS,fout);
        fputc(IK_SHOWJPG,fout);
        len_byte_code += 2;
        i = get_token(text,token,i);
        expected("(",token);
        i = get_string_expression(text, i);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_expression(text, i);
        i = get_token(text,token,i);
        expected(",",token);
        i = get_expression(text, i);
        i = get_token(text,token,i);
        expected(",",token);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        USE_GRAPHICS = TRUE;
        parse_text(text,i+1);
      }
    else if (strcmp("MP3.PLAY",token) == 0)
      {
        //printf("PLAYMP3\n");
        num_statements++;
        fputc(ID_MM,fout);
        fputc(IK_PLAYMP3,fout);
        len_byte_code += 2;
        i = get_token(text,token,i);
        expected("(",token);
        i = get_string_expression(text, i);
        i = get_token(text,token,i);
        expected(",",token);
        temp_brace = nobrace;
        nobrace = TRUE;
        i = get_expression(text, i);
        nobrace = temp_brace;
        USE_MM = TRUE;
        parse_text(text,i+1);
      }
      /** END IF PLAYMP3 **/
    else if (strcmp("MP3.FREE",token) == 0)
      {
        //printf("FREEMP3\n");
        num_statements++;
        fputc(ID_MM,fout);
        fputc(IK_FREEMP3,fout);
        len_byte_code += 2;
        parse_text(text,i);
      }
    else if (strcmp("MP3.REPLAY",token) == 0)
      {
        //printf("FREEMP3\n");
        num_statements++;
        fputc(ID_MM,fout);
        fputc(IK_REPLAYMP3,fout);
        len_byte_code += 2;
        parse_text(text,i);
      }
    else if (strcmp("DECLARE",token) == 0)
      {
        //printf("DECLARE\n");
        i = get_token(text,token,i);
        if (strcmp("SUB",token) == 0)
           {
           }
      }
    else if (strcmp("SHELL",token) == 0)
      {
        //printf("SHELL\n");
        num_statements++;
        fputc(ID_ANSI,fout);
        fputc(IK_SHELL,fout);
        len_byte_code += 2;
        i = get_string_expression(text, i);
        parse_text(text,i);
      }

      /** END IF DO **/

    /** VARIABLE/LABEL CHECKS **/
    else
      {
        if (rvalue == FALSE && text[i] == ':')
          {
            token[strlen(token)+1] = 0;
            token[strlen(token)] = ':';
          }
        done = FALSE;
        for (n=0;n<max_strvar;n++)
          {
            if (strcmp(token,(charstack+4*n)->name) == 0)
              {
                if (rvalue == TRUE)
                  {
                    fputc(ID_ANSI,fout);
                    fputc(IK_PRINT_NOCRLF,fout);
                    fputc(DT_STREXPR,fout);
                    len_byte_code += 3;
                    i = i - strlen(token);
                    i = get_string_expression(text,i);
                    if (text[i] != ';' && text[i] !=',')
                      {
                        fputc(ID_ANSI,fout);
                        fputc(IK_PRINT,fout);
                        fputc(DT_NONE,fout);
                        len_byte_code += 3;
                        if (text[i] == ':')
                          {
                            rvalue = FALSE;
                            parse_text(text, i+1);
                          }
                      }
                    else
                      parse_text(text,i+1);
                  }
                else
                  {
                    i = get_token(text, token, i);
                    expected("=",token);
                    fputc(ID_VARIABLE,fout);
                    fputc(IK_ASSIGNMENT,fout);
                    fputc(DT_STRING,fout);
                    word_num = n;
                    fwrite(&word_num,2,1,fout);
                    len_byte_code += 5;
                    rvalue = TRUE;
                    i = get_string_expression(text,i);
                    rvalue = FALSE;
                    if (text[i] == ':')
                         parse_text(text, i+1);
                  }
                  /** ENDIF ASSIGNMENT **/
                done = TRUE;
                break;
              }
              /** END IF STRING COMPARE **/
          }
          /** END FOR **/

        /** Check if it's a integer variable **/
        if (done == FALSE)
          {
            for (n=0;n<max_intvar;n++)
              {
                if (strcmp(token,(intstack+4*n)->name) == 0)
                  {
                    if (rvalue == TRUE)
                      {
                        fputc(ID_ANSI,fout);
                        fputc(IK_PRINT_NOCRLF,fout);
                        fputc(DT_EXPRESSION,fout);
                        len_byte_code += 3;
                        i = i - strlen(token);
                        i = get_expression(text,i);
                        if (text[i] != ';' && text[i] !=',')
                          {
                            fputc(ID_ANSI,fout);
                            fputc(IK_PRINT,fout);
                            fputc(DT_NONE,fout);
                            len_byte_code += 3;
                            if (text[i] == ':')
                              {
                                rvalue = FALSE;
                                parse_text(text, i+1);
                              }
                          }
                        else
                          parse_text(text,i+1);
                      }
                    else
                      {
                        i = get_token(text, token, i);
                        expected("=",token);
                        fputc(ID_VARIABLE,fout);
                        fputc(IK_ASSIGNMENT,fout);
                        temp_int = (intstack+4*n)->type;
                        switch (temp_int)
                          {
                            case DT_BYTE:
                              fputc(DT_BYTE,fout);
                              break;
                            case DT_INTEGER:
                              fputc(DT_INTEGER,fout);
                              break;
                            case DT_WORD:
                              fputc(DT_WORD,fout);
                              break;
                            case DT_DWORD:
                              fputc(DT_DWORD,fout);
                              break;
                            case DT_LONGINT:
                              fputc(DT_LONGINT,fout);
                              break;
                            case DT_SINGLE:
                              fputc(DT_SINGLE,fout);
                              break;
                            case DT_DOUBLE:
                              fputc(DT_DOUBLE,fout);
                              break;
                            case DT_EXT:
                              fputc(DT_EXT,fout);
                              break;
                          }
                        word_num = n;
                        fwrite(&word_num,2,1,fout);
                        rvalue = TRUE;
                        i = get_expression(text, i);
                        rvalue = FALSE;
                        len_byte_code += 5;
                        if (text[i] == ':')
                            parse_text(text, i+1);
                      }
                    done = TRUE;
                    break;
                  }
                  /** END IF INTEGER COMPARE **/
              }
              /** END FOR **/
          }
          /** END IF DONE **/

        if (done == FALSE)
          {
            for (n=0;n<max_arrintvar;n++)
              {
                if (strcmp(token,(arrintstack+n*4)->name) == 0)
                  {
                    if (rvalue == TRUE)
                      {
                        fputc(ID_ANSI,fout);
                        fputc(IK_PRINT_NOCRLF,fout);
                        fputc(DT_EXPRESSION,fout);
                        len_byte_code += 3;
                        i = i - strlen(token);
                        i = get_expression(text,i);
                        if (text[i] != ';' && text[i] !=',')
                          {
                            fputc(ID_ANSI,fout);
                            fputc(IK_PRINT,fout);
                            fputc(DT_NONE,fout);
                            len_byte_code += 3;
                            if (text[i] == ':')
                              {
                                rvalue = FALSE;
                                parse_text(text, i+1);
                              }
                          }
                        else
                          parse_text(text,i+1);
                      }
                    else
                      {
                        fputc(ID_VARIABLE,fout);
                        fputc(IK_ASSIGNMENT,fout);
                        fputc(DT_ARRAY,fout);
                        fputc(DT_INTEGER,fout);
                        word_num = n;
                        fwrite(&word_num,2,1,fout);
                          //temp_int = (arrintstack+4*n)->type;
                        len_byte_code += 6;
                        i = get_token(text,token,i);
                        expected("(",token);
                        temp_brace = nobrace;
                        nobrace = TRUE;
                        i = get_expression(text,i);
                        nobrace = temp_brace;
                        i = get_token(text,token,i);
                        expected(")",token);
                        i = get_token(text,token,i);
                        expected("=",token);
                        rvalue = TRUE;
                        i = get_expression(text, i);
                        rvalue = FALSE;
                        if (text[i] == ':')
                            parse_text(text, i+1);
                      }
                      /** END ELSE **/
                    done = TRUE;
                    break;
                  }
                  /** END IF STRCMP **/
              }
              /** END FOR **/
          }
          /** END IF DONE **/

        if (done == FALSE)
          {
            for (n=0;n<max_arrstrvar;n++)
              {
                if (strcmp(token,(arrcharstack+n*4)->name) == 0)
                  {
                    if (rvalue == TRUE)
                      {
                        fputc(ID_ANSI,fout);
                        fputc(IK_PRINT_NOCRLF,fout);
                        fputc(DT_STREXPR,fout);
                        len_byte_code += 3;
                        i = i - strlen(token);
                        i = get_string_expression(text,i);
                        if (text[i] != ';' && text[i] !=',')
                          {
                            fputc(ID_ANSI,fout);
                            fputc(IK_PRINT,fout);
                            fputc(DT_NONE,fout);
                            len_byte_code += 3;
                            if (text[i] == ':')
                              {
                                rvalue = FALSE;
                                parse_text(text, i+1);
                              }
                          }
                        else
                          parse_text(text,i+1);
                      }
                    else
                      {
                        fputc(ID_VARIABLE,fout);
                        fputc(IK_ASSIGNMENT,fout);
                        fputc(DT_ARRAY,fout);
                        fputc(DT_STRING,fout);
                        word_num = n;
                        fwrite(&word_num,2,1,fout);
                          //temp_int = (arrcharstack+4*n)->type;
                        len_byte_code += 6;
                        i = get_token(text,token,i);
                        expected("(",token);
                        temp_brace = nobrace;
                        nobrace = TRUE;
                        i = get_expression(text,i);
                        nobrace = temp_brace;
                        i = get_token(text,token,i);
                        expected(")",token);
                        i = get_token(text,token,i);
                        expected("=",token);
                        rvalue = TRUE;
                        i = get_string_expression(text, i);
                        rvalue = FALSE;
                        if (text[i] == ':')
                            parse_text(text, i+1);
                      }
                      /** END ELSE **/
                    done = TRUE;
                    break;
                  }
                  /** END IF STRCMP **/
              }
              /** END FOR **/
          }
          /** END IF DONE **/

        if (done == FALSE)
          {
            if (rvalue == TRUE || (token[strlen(token)-1] != ':' && isdigit(token[0]) == 0 && token[0] != '.'))
              {
                //printf("Line %ld: Statement, unknown variable name %s\n",line,token);
                //exit(EXIT_FAILURE);
                DIM_inplace(token);
                i = i - strlen(token);
                parse_text(text,i);
              }
            else
              {
                if (token[strlen(token)-1] == ':')
                  token[strlen(token)-1] = 0;
                add_labels(token, len_byte_code);
                resolve_branches();
                parse_text(text,i);
              }
          }
      }
      /** END ELSE **/


    free(token);
    free(variable);

    return 0;
  }
/** END PARSE_TEXT **/


int main (int argc, char *argv[])
{
  char *text = (char*)malloc(MAXLINE);
  char *outfilename = (char*)malloc(256);
  int i=0;
  float t1,t2;
  FILE *outfile;

  printf("BASIC Emulation Compiler %s (c)1998-99 William Yu\n",VERSION);
  if (argc == 1)
    {
       #if defined(USE_UNIX)
         printf("Usage: BEC infile.ext [outfile]\n");
       #else
         printf("Usage: BEC infile.ext [outfile.exe]\n");
       #endif
       exit(EXIT_FAILURE);
    }
    /** END IF **/

  printf("\nCompiling: %s",argv[1]);
  if ((fp = fopen(argv[1], "rb")) == NULL)
    {
       printf("\nFile does not exist\n");
       exit(EXIT_FAILURE);
    }
    /** END IF **/

  if (argc >= 3)
    {
       outfile = fopen(argv[2], "wb+");
       printf(" to %s\n",argv[2]);
       strcpy(outfilename, argv[2]);
    }
  else
    {
       printf(" to ");
       for (i=0;i<=strlen(argv[1]);i++)
         {
            if (*(argv[1]+i) == '.') break;
            text[i] = *(argv[1]+i);
         }
       #if !defined(USE_UNIX)
         text[i++] = '.';
         text[i++] = 'e';
         text[i++] = 'x';
         text[i++] = 'e';
       #endif
       text[i] = 0;
       printf("%s\n",text);
       strcpy(outfilename,text);
       outfile = fopen(text, "wb+");
    }
    /** END IF...ELSE **/
  
  fout = tmpfile();
  datafile = tmpfile();
  varlst = fopen("var.lst", "wb+");
  fprintf(varlst,"'Variable list for %s\n",argv[1]);

  charstack = malloc(4*char_stack_top);
  intstack = malloc(4*int_stack_top);
  arrcharstack = malloc(4*arrchar_stack_top);
  arrintstack = malloc(4*arrint_stack_top);
  conststack = malloc(4*const_stack_top);
  gotos = (struct labeltype*)malloc(4*gotos_stack_top);
  labels = (struct labeltype*)malloc(4*labels_stack_top);

  t1 = clock();
  while (read_line(text, MAXLINE) != -1)
    {
       line++;
       if (strlen(text) == 0) continue;
       //printf("line %ld:",line);
       //puts(text);
       rvalue = FALSE;
       nobrace = FALSE;
       parse_text(text,0);
    }
    /** END WHILE **/

  fputc(IK_END,fout);   /** Just in case user didn't end properly **/
  len_byte_code += 1;

  fseek(fout,0,SEEK_SET);
  fseek(datafile,0,SEEK_SET);
  fclose(fp);

  if (USE_MM == TRUE)
    {
      printf("Compiling using MM.LIB\n");
      if ((fp = fopen("mm.lib","rb")) == NULL)
        {
           printf("FATAL ERROR: Missing MM.LIB file\n");
           exit(EXIT_FAILURE);
        }
    }
  else if (USE_GRAPHICS == TRUE)
    {
      printf("Compiling using GRAPHICS.LIB\n");
      if ((fp = fopen("graphics.lib","rb")) == NULL)
        {
           printf("FATAL ERROR: Missing GRAPHICS.LIB file\n");
           exit(EXIT_FAILURE);
        }
    }
  else if (USE_DOS == TRUE)
    {
      printf("Compiling using DOS.LIB\n");
      if ((fp = fopen("dos.lib","rb")) == NULL)
        {
           printf("FATAL ERROR: Missing DOS.LIB file\n");
           exit(EXIT_FAILURE);
        }
    }
  else
    {
      printf("Compiling using standard ANSI.LIB\n");
      if ((fp = fopen("ansi.lib","rb")) == NULL)
        {
           printf("FATAL ERROR: Missing ANSI.LIB file\n");
           exit(EXIT_FAILURE);
        }
    }
    /** END IF..ELSE **/

  while ((i=fgetc(fp)) != EOF)    /** use fread/fwrite **/
    fputc(i,outfile);

  while ((i=fgetc(fout)) != EOF)      /** Bye code **/
    fputc(i,outfile);

  while ((i=fgetc(datafile)) != EOF)  /** Data **/
    fputc(i,outfile);

  fwrite(&len_data_seg,4,1,outfile);
  fwrite(&len_byte_code,4,1,outfile);

  fclose(fp);
  fclose(fout);
  fclose(datafile);
  fclose(outfile);

  if (resolve_stack != 0)
    {
      switch (resolve[resolve_stack-1].CNTRL_TAG)
        {
          case IK_FOR:
            printf("WARNING: Dangling FOR statement without NEXT\n");
            break;
          case IK_IF:
            printf("WARNING: Dangling IF statement without END IF\n");
            break;
          case IK_ELSE: case IK_ELSEIF:
            printf("WARNING: Dangling ELSE statement without END IF\n");
            break;
          case IK_WHILE:
            printf("WARNING: Dangling WHILE statement without WEND\n");
            break;
        }
    }
  else
    printf("Successful compile!\n");

//    printf("\nRemaining physical memory: %d", _go32_dpmi_remaining_physical_memory());
//    printf("\nRemaining virtual memory: %d\n\n", _go32_dpmi_remaining_virtual_memory());

  t2 = clock();
  t2 = (t2 - t1);
  printf("%ld statements, %ld lines        Compile time: %f\n", num_statements,line,(float)(t2/CLOCKS_PER_SEC));
  printf("Variables: %d strings, %d integers\n",max_strvar,max_intvar);
  printf("%ld bytes code, %ld bytes data\n",len_byte_code,bytes_data);

  #if defined(USE_UNIX)
    chmod(outfilename,448);
  #endif

  free(text);
  free(outfilename);

  return 0;
}
