/*
 * Copyright (c) 2006, Adam Dunkels
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */


//------------------------------------------------------------
// Changelog
//------------------------------------------------------------
//  [V:0.1 / 04.09.2013] :
// Author   : Adam Dunkels
// Web      : http://dunkels.com/adam/ubasic/
//
// original Version from Adam Dunkels without changings
//------------------------------------------------------------
//  [V:Minimal / 24.07.2015] :
// Author   : UB
// EMail    : mc-4u(@)t-online.de
// Web      : www.mikrocontroller-4u.de
// Port for STM32F429
//------------------------------------------------------------



#include "ubasic.h"
#include "tokenizer.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "stm32_ub_ubasic.h"


//------------------------------------------------------------
// pointer to BASIC-RAM
//------------------------------------------------------------
char *program_ptr;


//------------------------------------------------------------
// buffer for single string
//------------------------------------------------------------
#define MAX_STRINGLEN 85
static char string[MAX_STRINGLEN];


//------------------------------------------------------------
// GOSUB Buffer
//------------------------------------------------------------
#define MAX_GOSUB_STACK_DEPTH 10
static int gosub_stack[MAX_GOSUB_STACK_DEPTH];
static int gosub_stack_ptr;


//------------------------------------------------------------
// FOR Buffer
//------------------------------------------------------------
struct for_state {
  int line_after_for;
  int for_variable;
  int to;
  int step;
};
#define MAX_FOR_STACK_DEPTH 4
static struct for_state for_stack[MAX_FOR_STACK_DEPTH];
static int for_stack_ptr;

//------------------------------------------------------------
// int-variables
//------------------------------------------------------------
#define MAX_VARNUM 26  // dont change this value
static int int_var[MAX_VARNUM];

//------------------------------------------------------------
// added by UB
// string-variables
//------------------------------------------------------------
static char str_var[MAX_VARNUM][MAX_STRINGLEN];
char strbuf1[MAX_STRINGLEN]; // str buffer
char strbuf2[MAX_STRINGLEN]; // str buffer






//------------------------------------------------------------
static int ended;
static int failed, akt_linenum;       // added by UB


//------------------------------------------------------------
static int expr(void);
static char *strexpr(void); // added by UB
static void linenum_statement(void);
static void statement(void);
static void skipelse(void);  // added by UB
static void string_to_cmd(char *ptr, char mode); // added by UB


//------------------------------------------------------------
// added by UB
// basic commands with integer return value
// USER : add here new functions with return value <int>
//------------------------------------------------------------
static int cmd_abs(void);



//------------------------------------------------------------
// added by UB
// basic commands with string return value
// USER : add here new functions with return value <string>
//------------------------------------------------------------
static char *cmd_rightstr(void);



//------------------------------------------------------------
// init
// mode : 0=reset variable
//        1=variable dont change (for inline interpreter)
//------------------------------------------------------------
void ubasic_init(char *program, int mode)
{
  int n;

  program_ptr = program;
  for_stack_ptr = gosub_stack_ptr = 0;
  ended = 0;
  failed =0;
  akt_linenum =0;
  // pre-parse the basic-program
  n=tokenizer_pre_parse(program);
  if(n!=0) {
    failed=UBASIC_PREPARSE_ERR;
    akt_linenum=tokenizer_linenum();
  }

  if(mode==0) {
    for(n=0;n<MAX_VARNUM;n++) {
      // integer variables
      int_var[n]=0;
      // string variables
      str_var[n][0]=0x00;
    }
  }
}
//------------------------------------------------------------
// check if token on the right place
//------------------------------------------------------------
static void accept(int token)
{
  if(token != tokenizer_token()) {
    tokenizer_error_print();
    failed=UBASIC_UNEXPECTED_TOKEN;
  }
  else {
    tokenizer_next();
  }
}
//------------------------------------------------------------
// return a value from a integer variable 'a' to 'z'
//------------------------------------------------------------
static int varfactor(void)
{
  int r;
  r = ubasic_get_int_var(tokenizer_variable_num());
  accept(TOKENIZER_VARIABLE);
  return r;
}
//------------------------------------------------------------
// return factor
// insert all cases in "void tokenizer_set_expression(void)"
// USER : insert all new functions with ret_value <int>
//------------------------------------------------------------
static int factor(void)
{
  int r=0;
  int mode=0;

  if(tokenizer_token()==TOKENIZER_MINUS) {
    // negativ
    mode=1;
    accept(TOKENIZER_MINUS);
  }

  switch(tokenizer_token()) {
    case TOKENIZER_NUMBER:  // '1234'
      r = tokenizer_num();
      accept(TOKENIZER_NUMBER);
    break;
    case TOKENIZER_HEXNUM:  // '0x1234'
      r = tokenizer_hexnum();
      accept(TOKENIZER_HEXNUM);
    break;
    case TOKENIZER_LEFTPAREN: // '(r)'
      accept(TOKENIZER_LEFTPAREN);
      r = expr();
      accept(TOKENIZER_RIGHTPAREN);
    break;
    case TOKENIZER_VARIABLE: // 'a'
      r = varfactor();
    break;
    case TOKENIZER_ABS : // 'ABS'
      r=cmd_abs();
    break;  
    default:
      failed=UBASIC_UNEXPECTED_TOKEN;
    break;
  }

  if(mode==1) r=0-r; // negation

  return r;
}
//------------------------------------------------------------
// calculate
// multiplication '*'
// division       '/'
// modulo         '%'
//------------------------------------------------------------
static int term(void)
{
  int f1, f2;
  int op;

  f1 = factor();
  op = tokenizer_token();
  while(op == TOKENIZER_ASTR ||
	op == TOKENIZER_SLASH ||
	op == TOKENIZER_MOD) {
    tokenizer_next();
    f2 = factor();
    switch(op) {
    case TOKENIZER_ASTR: // '*'
      f1 = f1 * f2;
      break;
    case TOKENIZER_SLASH:  // '/'
      f1 = f1 / f2;
      break;
    case TOKENIZER_MOD:  // '%'
      f1 = f1 % f2;
      break;
    }
    op = tokenizer_token();
  }
  return f1;
}
//------------------------------------------------------------
// calculate
// plus        '+'
// minus       '-'
// logical AND '&'
// logical OR  '|'
// logical XOR '^'
//------------------------------------------------------------
static int expr(void)
{
  int t1, t2;
  int op;

  t1 = term();
  op = tokenizer_token();
  while(op == TOKENIZER_PLUS ||
    op == TOKENIZER_MINUS ||
    op == TOKENIZER_AND ||
    op == TOKENIZER_OR ||
    op == TOKENIZER_XOR) {
    tokenizer_next();
    t2 = term();
    switch(op) {
    case TOKENIZER_PLUS:  // '+'
      t1 = t1 + t2;
      break;
    case TOKENIZER_MINUS:  // '-'
      t1 = t1 - t2;
      break;
    case TOKENIZER_AND:  // '&'
      t1 = t1 & t2;
      break;
    case TOKENIZER_OR:  // '|'
      t1 = t1 | t2;
      break;
    case TOKENIZER_XOR:  // '^'
      t1 = t1 ^ t2;
      break;
    }
    op = tokenizer_token();
  }
  return t1;
}
//------------------------------------------------------------
// read one string
// insert all cases in "void tokenizer_set_expression(void)"
// USER : insert all new functions with ret_value <string>
//------------------------------------------------------------
static char *strpart(void)
{
  char *r;

  switch(tokenizer_token()) {
    case TOKENIZER_STRING : // 'Test'
      tokenizer_string(string, sizeof(string));
      r=string;
      tokenizer_next();
    break;
    case TOKENIZER_STRINGVAR : // 'a$'
      ubasic_get_str_var(tokenizer_variable_num());
      r=string;
      tokenizer_next();
    break;
    case TOKENIZER_RIGHTSTR : // 'RIGHT$'
      r=cmd_rightstr();
    break;   
    default:
      failed=UBASIC_UNEXPECTED_TOKEN;
  }

  return r;
}
//------------------------------------------------------------
// cat strings
// plus        '+'
//------------------------------------------------------------
static char *strexpr(void)
{
  char s1[MAX_STRINGLEN+1];
  char s2[MAX_STRINGLEN+1];
  int len1,len2;
  int op;

  strcpy(s1, strpart());
  len1=strlen(s1);
  op = tokenizer_token();
  while(op == TOKENIZER_PLUS) { // '+'
    tokenizer_next();
    strcpy(s2, strpart());
    len2=strlen(s2);
    if(len1+len2<MAX_STRINGLEN) {
      strcat(s1, s2);
      len1=strlen(s1);
    }
    else failed=UBASIC_OVERFLOW;

    op = tokenizer_token();
  }
  strcpy(strbuf1, s1);
  return strbuf1;
}
//------------------------------------------------------------
// check relation
// equal  '='
// smaler '<'
// bigger '>'
//------------------------------------------------------------
static int relation(void)
{
  int r1, r2;
  int op;

  r1 = expr();
  op = tokenizer_token();
  while(op == TOKENIZER_LT ||
	op == TOKENIZER_GT ||
	op == TOKENIZER_EQ) {
    tokenizer_next();
    r2 = expr();
    switch(op) {
    case TOKENIZER_LT: // '<'
      r1 = r1 < r2;
      break;
    case TOKENIZER_GT:  // '>'
      r1 = r1 > r2;
      break;
    case TOKENIZER_EQ:  // '='
      r1 = r1 == r2;
      break;
    }
    op = tokenizer_token();
  }
  return r1;
}
//------------------------------------------------------------
// check string relation
// equal  '='  "A"="A"
// smaler '<'  "A"<"B"
// bigger '>'  "B">"A"
//------------------------------------------------------------
static int strrelation(void)
{
  char s1[MAX_STRINGLEN+1];
  char s2[MAX_STRINGLEN+1];
  int r1=0, r2;
  int op;

  strcpy(s1, strexpr());
  op = tokenizer_token();
  while(op == TOKENIZER_LT ||
	op == TOKENIZER_GT ||
	op == TOKENIZER_EQ) {
    tokenizer_next();
    strcpy(s2, strexpr());
    r2=strcmp(s1, s2);
    switch(op) {
    case TOKENIZER_LT:  // '<'
      if(r2<0) r1=1;
      break;
    case TOKENIZER_GT:  // '>'
      if(r2>0) r1=1;
      break;
    case TOKENIZER_EQ:  // '='
      if(r2==0) r1=1;
      break;
    }
    op = tokenizer_token();
  }

  return r1;
}
//------------------------------------------------------------
// jump to line-nummer (linenum)
//------------------------------------------------------------
static void jump_linenum(int linenum)
{
  int ok=0,akt_token,aktline;

  // try to jump from a pre-parsed linenumber
  ok=tokenizer_jumpfast(linenum);
  if(ok==1) return;

  // search the linenumber manually
  tokenizer_init(program_ptr);

  ok=0;
  do {
    akt_token=tokenizer_token();
    if(akt_token==TOKENIZER_ERROR) {
      ok=2;
    }
    else if(akt_token==TOKENIZER_ENDOFINPUT) {
      ok=1;
    }
    else if(akt_token==TOKENIZER_LINENUM) {
      aktline=tokenizer_num();
      if(aktline==linenum)  {
        ok=3;
      }
      else {
        tokenizer_skipline();
        tokenizer_next();
      }
    }
    else {
      ok=4;
    }
  }while(ok==0);
}
//------------------------------------------------------------
// Statement : "GOTO"
// Syntax    : GOTO<uint>
// Return    : <void>
//------------------------------------------------------------
static void goto_statement(void)
{
  accept(TOKENIZER_GOTO);
  jump_linenum(tokenizer_num());
}
//------------------------------------------------------------
// Statement : "PRINT"
// Syntax    : PRINT<printable>[<tr><printable>...]
// Return    : <void>
//------------------------------------------------------------
static void print_statement(void)
{
  int newline=1;

  accept(TOKENIZER_PRINT);
  do {
    if(tokenizer_token() == TOKENIZER_STRING) {
      tokenizer_string(string, sizeof(string));
      string_to_cmd(string,0);
      newline=1;
      tokenizer_next();
    } else if(tokenizer_is_expr()==1) { // integer expression
      sprintf(string,"%d",expr());
      string_to_cmd(string,0);
      newline=1;
    } else if(tokenizer_is_expr()==2) { // string expression
      sprintf(string,"%s",strexpr());
      string_to_cmd(string,0);
      newline=1;
    } else if(tokenizer_token()==TOKENIZER_LEFTPAREN) {
      sprintf(string,"%d",expr());
      string_to_cmd(string,0);
      newline=1;
    } else if(tokenizer_token() == TOKENIZER_COMMA) {
      string_to_cmd("",1);
      newline=0;
      tokenizer_next();
    } else if(tokenizer_token() == TOKENIZER_SEMICOLON) {
      newline=0;
      tokenizer_next();
    } else {
      break;
    }
  } while(tokenizer_token() != TOKENIZER_CR &&
	  tokenizer_token() != TOKENIZER_ENDOFINPUT);

  if(newline==1) string_to_cmd("",2);

  if(tokenizer_token()!=TOKENIZER_ELSE) {
    tokenizer_next();
  }
}
//------------------------------------------------------------
// this is a subfunction from "PRINT"
// mode : 0 = normal
// mode : 1 = TAB
// mode : 2 = Newline
//------------------------------------------------------------
static void string_to_cmd(char *ptr, char mode)
{
  #if USE_UART_AT_PRINT==1
    // print fuer UART
    if(mode==0) { // without newline
      UB_Uart_SendString(COM1,ptr,NONE);
    }
    else if(mode==2) { // with Newline
      UB_Uart_SendString(COM1,ptr,CRLF);
    }
    else { // with TAB (not supported at UART)
      UB_Uart_SendString(COM1," ",NONE);
      UB_Uart_SendString(COM1,ptr,CRLF);
    }
  #endif
}
//------------------------------------------------------------
// Statement : "IF"
// Syntax    : IF<int_expr><rel><int_expr>[THEN]<cmd>[ELSE<cmd>]
//     or    : IF<str_expr><rel><str_expr>[THEN]<cmd>[ELSE<cmd>]
// Return    : <void>
//------------------------------------------------------------
static void if_statement(void)
{
  int r=0;

  accept(TOKENIZER_IF);

  if(tokenizer_is_expr()==1) { // integer expression
    r = relation();
  }
  else if(tokenizer_is_expr()==2) { // string expression
    r = strrelation();
  }
  else if(tokenizer_token()==TOKENIZER_LEFTPAREN) {
    r = relation();
  }
  else failed=UBASIC_UNEXPECTED_TOKEN;

  if(tokenizer_token()==TOKENIZER_THEN) {
    accept(TOKENIZER_THEN);
  }
  if(r) {
    statement();
    if(tokenizer_token()==TOKENIZER_ELSE) {
      skipelse();
    }
  }
  else {
    do {
      tokenizer_next();
    } while(tokenizer_token() != TOKENIZER_ELSE &&
	    tokenizer_token() != TOKENIZER_CR &&
	    tokenizer_token() != TOKENIZER_ENDOFINPUT);

    if(tokenizer_token() == TOKENIZER_ELSE) {
      tokenizer_next();
      statement();
    } else if(tokenizer_token() == TOKENIZER_CR) {
      tokenizer_next();
    }
  }
}
//------------------------------------------------------------
// Statement : "LET"
// Syntax    : [LET]<int_var>=<int_expr>
//    or       [LET]<str_var>=<str_expr>
// Return    : <void>
//------------------------------------------------------------
static void
let_statement(void)
{
  int var,akt_token;

  akt_token=tokenizer_token();
  if(akt_token==TOKENIZER_VARIABLE) {
    // interger var
    var = tokenizer_variable_num();
    accept(TOKENIZER_VARIABLE);
    accept(TOKENIZER_EQ);
    ubasic_set_int_var(var, expr());
  }
  else if(akt_token==TOKENIZER_STRINGVAR) {
    // string var
    var = tokenizer_variable_num();
    accept(TOKENIZER_STRINGVAR);
    accept(TOKENIZER_EQ);
    ubasic_set_str_var(var, strexpr());
  }
  else failed=UBASIC_UNEXPECTED_TOKEN;

  if(tokenizer_token()!=TOKENIZER_ELSE) {
    accept(TOKENIZER_CR);
  }
}
//------------------------------------------------------------
// Statement : "GOSUB"
// Syntax    : GOSUB<uint>
// Return    : <void>
//------------------------------------------------------------
static void gosub_statement(void)
{
  int linenum;
  accept(TOKENIZER_GOSUB);
  linenum = tokenizer_num();
  accept(TOKENIZER_NUMBER);

  if(tokenizer_token()!=TOKENIZER_ELSE) {
    accept(TOKENIZER_CR);
  }
  else {
    skipelse();
  }

  if(gosub_stack_ptr < MAX_GOSUB_STACK_DEPTH) {
    gosub_stack[gosub_stack_ptr] = tokenizer_num();
    gosub_stack_ptr++;
    jump_linenum(linenum);
  }
  else failed=UBASIC_OVERFLOW;
}
//------------------------------------------------------------
// Statement : "RETURN"
// Syntax    : RETURN
// Return    : <void>
//------------------------------------------------------------
static void return_statement(void)
{
  accept(TOKENIZER_RETURN);
  if(gosub_stack_ptr > 0) {
    gosub_stack_ptr--;
    jump_linenum(gosub_stack[gosub_stack_ptr]);
  }
  else failed=UBASIC_UNEXPECTED_TOKEN;
}
//------------------------------------------------------------
// Statement : "NEXT"
// Syntax    : NEXT<int_var>
// Return    : <void>
//------------------------------------------------------------
static void next_statement(void)
{
  int var,ist,soll,step;

  accept(TOKENIZER_NEXT);
  var = tokenizer_variable_num();
  accept(TOKENIZER_VARIABLE);
  if(for_stack_ptr > 0 &&
    var == for_stack[for_stack_ptr - 1].for_variable) {

    ist=ubasic_get_int_var(var);
    soll=for_stack[for_stack_ptr - 1].to;
    step=for_stack[for_stack_ptr - 1].step;

    if(ist<soll) {
      // count up
      ubasic_set_int_var(var,ist + step);
      if(ubasic_get_int_var(var) <= for_stack[for_stack_ptr - 1].to) {
        jump_linenum(for_stack[for_stack_ptr - 1].line_after_for);
      } else {
        for_stack_ptr--;
        accept(TOKENIZER_CR);
      }
    }
    else if(ist>soll) {
      // count down
      ubasic_set_int_var(var,ist - step);
      if(ubasic_get_int_var(var) >= for_stack[for_stack_ptr - 1].to) {
        jump_linenum(for_stack[for_stack_ptr - 1].line_after_for);
      } else {
        for_stack_ptr--;
        accept(TOKENIZER_CR);
      }
    }
    else {
      for_stack_ptr--;
      accept(TOKENIZER_CR);
    }

  } else {
    accept(TOKENIZER_CR);
  }

}
//------------------------------------------------------------
// Statement : "FOR"
// Syntax    : FOR<int_var>=<int_expr>TO<int_expr>[STEP<int_expr>]
// Return    : <void>
//------------------------------------------------------------
static void for_statement(void)
{
  int for_variable, to, step=1;

  accept(TOKENIZER_FOR);
  for_variable = tokenizer_variable_num();
  accept(TOKENIZER_VARIABLE);
  accept(TOKENIZER_EQ);
  ubasic_set_int_var(for_variable, expr());
  accept(TOKENIZER_TO);
  to = expr();
  if(tokenizer_token()!=TOKENIZER_ELSE) {
    if(tokenizer_token()==TOKENIZER_STEP) {
      accept(TOKENIZER_STEP);
      step = expr();
      if(step<=0) step=1;
      if(tokenizer_token()!=TOKENIZER_ELSE) {
        accept(TOKENIZER_CR);
      }
      else {
        skipelse();
      }
    }
    else {
      accept(TOKENIZER_CR);
    }
  }
  else {
    skipelse();
  }

  if(for_stack_ptr < MAX_FOR_STACK_DEPTH) {
    for_stack[for_stack_ptr].line_after_for = tokenizer_num();
    for_stack[for_stack_ptr].for_variable = for_variable;
    for_stack[for_stack_ptr].to = to;
    for_stack[for_stack_ptr].step = step;

    for_stack_ptr++;
  }
  else failed=UBASIC_OVERFLOW;
}
//------------------------------------------------------------
// Statement : "END"
// Syntax    : END
// Return    : <void>
//------------------------------------------------------------
static void end_statement(void)
{
  accept(TOKENIZER_END);
  ended = 1;
}


//------------------------------------------------------------
// NEW <VOID> STATEMENTS BY UB
// USER : add here your new functions with return_value <void>
//------------------------------------------------------------


//------------------------------------------------------------
// Statement : "REM"
// Syntax    : REM<anything>
// Return    : <void>
//------------------------------------------------------------
static void rem_statement(void)
{
  tokenizer_skipline();
  accept(TOKENIZER_CR);
}




//------------------------------------------------------------
// NEW <INTEGER> STATEMENTS BY UB
// USER : add here your new functions with return_value <int>
//------------------------------------------------------------

//------------------------------------------------------------
// Statement : "ABS"
// Syntax    : ABS(<int_expr>)
// Return    : <int>
//------------------------------------------------------------
static int cmd_abs(void)
{
  int ret_value=0;

  accept(TOKENIZER_ABS);
  accept(TOKENIZER_LEFTPAREN);
  ret_value=expr();
  accept(TOKENIZER_RIGHTPAREN);
  if(ret_value<0) ret_value=0-ret_value;

  return ret_value;
}





//------------------------------------------------------------
// NEW <STRING> STATEMENTS BY UB
// USER : add here your new functions with return_value <string>
//------------------------------------------------------------


//------------------------------------------------------------
// Statement : "RIGHTSTR"
// Syntax    : RIGHT$(<str_expr>,<int_expr>)
// Return    : <str>
//------------------------------------------------------------
static char *cmd_rightstr(void)
{
  char *ret_wert,*s;
  int count,length,n,start;

  strbuf2[0]=0x00;
  ret_wert=(char*)&strbuf2[0];

  accept(TOKENIZER_RIGHTSTR);
  accept(TOKENIZER_LEFTPAREN);
  s=strexpr();
  length=strlen(s);
  accept(TOKENIZER_COMMA);
  count=expr();
  if(count<=0) failed=UBASIC_INVALID_DATA;
  accept(TOKENIZER_RIGHTPAREN);
  if((failed==0) && (length>0)) {
    if(count>=length) {
      ret_wert=s;
    }
    else {
      start=length-count;
      for(n=0;n<count;n++) {
        strbuf2[n]=s[n+start];
      }
      strbuf2[n]=0x00;
      ret_wert=(char*)&strbuf2[0];
    }
  }

  return ret_wert;
}



//------------------------------------------------------------
// END OF NEW STATEMENTS BY UB
//------------------------------------------------------------




//------------------------------------------------------------
// search target statement
//------------------------------------------------------------
static void statement(void)
{
  int token;

  if(failed!=0) return;

  token = tokenizer_token();

  switch(token) {
  case TOKENIZER_PRINT:
    print_statement();
    break;
  case TOKENIZER_IF:
    if_statement();
    break;
  case TOKENIZER_GOTO:
    goto_statement();
    break;
  case TOKENIZER_GOSUB:
    gosub_statement();
    break;
  case TOKENIZER_RETURN:
    return_statement();
    break;
  case TOKENIZER_FOR:
    for_statement();
    break;
  case TOKENIZER_NEXT:
    next_statement();
    break;
  case TOKENIZER_END:
    end_statement();
    break;
  case TOKENIZER_LET:
    accept(TOKENIZER_LET);
    /* Fall through. */
  case TOKENIZER_VARIABLE:
  case TOKENIZER_STRINGVAR:
    let_statement();
    break;
  //----------------------------------------
  // NEW TOKENS WIHTOUT RETURN VALUES BY UB
  // USER : insert all new functions with ret_value <void>
  //----------------------------------------
  case TOKENIZER_REM :
    rem_statement();
    break;    
  //----------------------------------------
  default:
    failed=UBASIC_INVALID_KEYWORD;
  }
}
//------------------------------------------------------------
static void linenum_statement(void)
{
  if(failed==0) {
    if(tokenizer_num()!=0) akt_linenum = tokenizer_num();
  }
  accept(TOKENIZER_LINENUM);
  statement();
  return;
}
//------------------------------------------------------------
void ubasic_run(void)
{
  if(tokenizer_finished()) {
    return;
  }

  linenum_statement();
}
//------------------------------------------------------------
int ubasic_finished(void)
{
  return ended || tokenizer_finished() || failed;
}
//------------------------------------------------------------
void ubasic_set_int_var(int varnum, int value)
{
  if(varnum >= 0 && varnum <= MAX_VARNUM) {
    int_var[varnum] = value;
  }
  else failed=UBASIC_INVALID_DATA;
}
//------------------------------------------------------------
int ubasic_get_int_var(int varnum)
{
  if(varnum >= 0 && varnum <= MAX_VARNUM) {
    return int_var[varnum];
  }
  else failed=UBASIC_INVALID_DATA;

  return 0;
}
//------------------------------------------------------------



//------------------------------------------------------------
// NEW FUNCTIONS BY UB
//------------------------------------------------------------


//------------------------------------------------------------
void ubasic_set_str_var(int varnum, char *ptr)
{
  if(varnum >= 0 && varnum <= MAX_VARNUM) {
    strcpy(str_var[varnum], ptr);
  }
  else failed=UBASIC_INVALID_DATA;
}
//------------------------------------------------------------
char *ubasic_get_str_var(int varnum)
{
  string[0]=0x00;
  if(varnum >= 0 && varnum <= MAX_VARNUM) {
    strcpy(string,str_var[varnum]);
  }
  else failed=UBASIC_INVALID_DATA;

  return string;
}
//------------------------------------------------------------
static void skipelse(void)
{
  do {
    tokenizer_next();
  } while(tokenizer_token() != TOKENIZER_CR &&
          tokenizer_token() != TOKENIZER_ENDOFINPUT);

  if(tokenizer_token() == TOKENIZER_CR) {
    accept(TOKENIZER_CR);
  }
}
//------------------------------------------------------------
int ubasic_failed(void)
{
  return failed;
}
//------------------------------------------------------------
int ubasic_linenum(void)
{
  return akt_linenum;
}
//------------------------------------------------------------
int ubasic_getkeyword(char token, char *ptr)
{
  int ret_wert;

  ret_wert=tokenizer_getkeyword(token, ptr);

  return ret_wert;
}
