示例#1
0
文件: ubasic.c 项目: CobooGuo/ubasic
/*---------------------------------------------------------------------------*/
static void
if_statement(void)
{
  int r;

  accept(TOKENIZER_IF);

  r = relation();
  DEBUG_PRINTF("if_statement: relation %d\n", r);
  accept(TOKENIZER_THEN);
  if(r) {
    statement();
  } 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();
    }
  }
}
示例#2
0
//static void print_statement(void)
void print_statement(void)
{
	char buf[20];
	accept(TOKENIZER_PRINT);
	do {
		if(tokenizer_token() == TOKENIZER_STRING) {
			tokenizer_string(strings[MAX_STRINGNUM], sizeof(strings[MAX_STRINGNUM]));
			glcd_PutsA(strings[MAX_STRINGNUM]);
			tokenizer_next();
		} else if(tokenizer_token() == TOKENIZER_COMMA) {
			glcd_PutsA(" ");
			tokenizer_next();
		} else if(tokenizer_token() == TOKENIZER_SEMICOLON) {
			tokenizer_next();
		} else if(tokenizer_token() == TOKENIZER_VARIABLE ||
				  tokenizer_token() == TOKENIZER_NUMBER) {
			glcd_PutsA(ltodeci(expr(),buf,6));
		} else {
			break;
		}
	} while(tokenizer_token() != TOKENIZER_CR &&
			tokenizer_token() != TOKENIZER_ENDOFINPUT);
	glcd_PutsA("\n");
//	cputs_p(6,"Print");
	tokenizer_next();
}
static void print_statement (void)
{
  accept(T_PRINT);
  do {
    /* Print a string literal. */
    if (tokenizer_token() == T_STRING)
    {
      printf("%s", tokenizer_string());
      tokenizer_next();
    }
    /* A seperator, send a space. */
    else if (tokenizer_token() == T_SEPERATOR)
    {
      printf(" ");
      tokenizer_next();
    }
    /* Evaluate and print an expression. */
    else if (tokenizer_token() == T_LETTER ||
    tokenizer_token() == T_NUMBER ||
    tokenizer_token() == T_LEFT_PAREN)
      printf("%d", expression());
    else
    {
      break;
    }
    /* This additionally ensures a new-line character
       is present at the end of the line-statement. */
    if (tokenizer_finished())
      accept(T_EOL);
  } while (tokenizer_token() != T_EOL &&
    tokenizer_token() != T_EOF);

  printf("\n");
  tokenizer_next();
}
示例#4
0
文件: ubasic.c 项目: CobooGuo/ubasic
/*---------------------------------------------------------------------------*/
static void
print_statement(void)
{
  accept(TOKENIZER_PRINT);
  do {
    DEBUG_PRINTF("Print loop\n");
    if(tokenizer_token() == TOKENIZER_STRING) {
      tokenizer_string(string, sizeof(string));
      printf("%s", string);
      tokenizer_next();
    } else if(tokenizer_token() == TOKENIZER_COMMA) {
      printf(" ");
      tokenizer_next();
    } else if(tokenizer_token() == TOKENIZER_SEMICOLON) {
      tokenizer_next();
    } else if(tokenizer_token() == TOKENIZER_VARIABLE ||
          tokenizer_token() == TOKENIZER_NUMBER) {
      printf("%d", expr());
    } else {
      break;
    }
  } while(tokenizer_token() != TOKENIZER_CR &&
      tokenizer_token() != TOKENIZER_ENDOFINPUT);
  printf("\n");
  DEBUG_PRINTF("End of print\n");
  tokenizer_next();
}
static void find_linenum (int linenum)
{
  /* Skip irrelevant new-lines and comments. */
  while (tokenizer_token() != T_NUMBER)
    tokenizer_next();
  while (tokenizer_num() != linenum &&
  tokenizer_token() != T_EOF)
  {
    /* Check line number, then skip the rest of line statement. */
    do {
      do {
        tokenizer_next();
      } while (tokenizer_token() != T_EOL &&
      tokenizer_token() != T_EOF);
      if (tokenizer_token() == T_EOL)
      {
        /* Skip irrelevant new-lines and comments. */
        while (tokenizer_token() != T_NUMBER &&
        tokenizer_token() != T_EOF)
          tokenizer_next();
      }
    } while (tokenizer_token() != T_NUMBER &&
      tokenizer_token() != T_EOF);
  }
}
示例#6
0
static void print_statement(void)
{
  uint8_t nonl;
  uint8_t t;
  uint8_t nv = 0;

  do {
    t = current_token;
    nonl = 0;
    DEBUG_PRINTF("Print loop\n");
    if (nv == 0) {
      if(t == TOKENIZER_STRING) {
        /* Handle string const specially - length rules */
        tokenizer_string_func(charout, NULL);
        tokenizer_next();
        nv = 1;
        continue;
      } else if(TOKENIZER_STRINGEXP(t)) {
        charoutstr(stringexpr());
        nv = 1;
        continue;
      } else if(TOKENIZER_NUMEXP(t)) {
        intout(intexpr());
        nv = 1;
        continue;
      } else if(t == TOKENIZER_TAB) {
        nv = 1;
        accept_tok(TOKENIZER_TAB);
        chartab(bracketed_intexpr());
        continue;
      } else if(t == TOKENIZER_AT) {
        int x,y;
        nv = 1;
        accept_tok(TOKENIZER_AT);
        y = intexpr();
        accept_tok(TOKENIZER_COMMA);
        x = intexpr();
        if (move_cursor(x,y))
          chpos = x;
        continue;
      }
    }
    nv = 0;
    if(t == TOKENIZER_COMMA) {
      charout('\t', NULL);
      nonl = 1;
      tokenizer_next();
    } else if(t == TOKENIZER_SEMICOLON) {
      nonl = 1;
      tokenizer_next();
    } else if (!statement_end()) {
      syntax_error();
      break;
    }
  } while(!statement_end());
  if (!nonl)
    charout('\n', 0);
  DEBUG_PRINTF("End of print\n");
}
示例#7
0
//static int expr(void)
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) {
		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;
		}
		op = tokenizer_token();
	}
	return t1;
}
示例#8
0
//static int term(void)
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;
}
示例#9
0
//static void accept(int token)
void accept(int token)
{
#if TEST
	char buf[10];
#endif
	if(token != tokenizer_token()) {
#if TEST
		buf[0] = (token/10) + '0';
		buf[1] = (token%10) + '0';
		buf[2] = ' ';
		buf[3] = (current_token/10) + '0';
		buf[4] = (current_token%10) + '0';
		buf[5] = '\n';
		buf[6] = 0x00;
//		printf(buf);
//		cputs_p(6,buf);
		glcd_PutsA(buf);
#endif
		tokenizer_error_print();
		ended = 1;
		glcd_DrawCursor();
	//	exit(1);
	}
	tokenizer_next();
}
示例#10
0
local size_t sentencizer_next(struct mascara *imp, struct mr_token **tks)
{
   struct sentencizer *szr = (struct sentencizer *)imp;
   struct sentence *sent = &szr->sent;

   assert(szr->str && "text no set");
   sentence_clear(sent);

   size_t len;
   const unsigned char *last_period;
   const unsigned char *str = next_sentence(szr, &len, &last_period);
   if (!str) {
      *tks = NULL;
      return 0;
   }
   size_t offset_incr = szr->offset_incr + str - szr->str;

   struct tokenizer tkr;
   tokenizer_init(&tkr, szr->vtab);
   tokenizer_set_text(&tkr.base, str, len, offset_incr);

   struct mr_token *tk;
   while (tokenizer_next(&tkr.base, &tk)) {
      if (tk->str == (const char *)last_period ||
         !sentencizer_reattach_period(sent, tk)) {
         sentence_add(sent, tk);
         if (sent->len == MR_MAX_SENTENCE_LEN) {
            szr->p = (const unsigned char *)tk->str + tk->len;
            break;
         }
      }
   }
   *tks = sent->tokens;
   return sent->len;
}
示例#11
0
文件: ubasic.c 项目: CobooGuo/ubasic
/*---------------------------------------------------------------------------*/
static int
relation(void)
{
  int r1, r2;
  int op;

  r1 = expr();
  op = tokenizer_token();
  DEBUG_PRINTF("relation: token %d\n", op);
  while(op == TOKENIZER_LT ||
       op == TOKENIZER_GT ||
       op == TOKENIZER_EQ) {
    tokenizer_next();
    r2 = expr();
    DEBUG_PRINTF("relation: %d %d %d\n", r1, op, r2);
    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;
}
示例#12
0
文件: ubasic.c 项目: CobooGuo/ubasic
/*---------------------------------------------------------------------------*/
static VARIABLE_TYPE
expr(void)
{
  int t1, t2;
  int op;

  t1 = term();
  op = tokenizer_token();
  DEBUG_PRINTF("expr: token %d\n", op);
  while(op == TOKENIZER_PLUS ||
       op == TOKENIZER_MINUS ||
       op == TOKENIZER_AND ||
       op == TOKENIZER_OR) {
    tokenizer_next();
    t2 = term();
    DEBUG_PRINTF("expr: %d %d %d\n", t1, op, t2);
    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;
    }
    op = tokenizer_token();
  }
  DEBUG_PRINTF("expr: %d\n", t1);
  return t1;
}
示例#13
0
文件: ubasic.c 项目: CobooGuo/ubasic
/*---------------------------------------------------------------------------*/
static int
term(void)
{
  int f1, f2;
  int op;

  f1 = factor();
  op = tokenizer_token();
  DEBUG_PRINTF("term: token %d\n", op);
  while(op == TOKENIZER_ASTR ||
       op == TOKENIZER_SLASH ||
       op == TOKENIZER_MOD) {
    tokenizer_next();
    f2 = factor();
    DEBUG_PRINTF("term: %d %d %d\n", f1, op, f2);
    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();
  }
  DEBUG_PRINTF("term: %d\n", f1);
  return f1;
}
static int term (void)
{
  int f1, f2, op;
  f1 = factor();
  op = tokenizer_token();
  while (op == T_ASTERISK ||
  op == T_SLASH)
  {
    tokenizer_next();
    f2 = factor();
    switch (op)
    {
      case T_ASTERISK:
        f1 = f1 * f2;
        break;
      case T_SLASH:
        if (f2 == 0)
        {
          /* Divide by zero. */
          dprintf(
            "*warning: divide by zero\n",
            E_WARNING);
          f1 = 0;
        }
        else
        {
          f1 = f1 / f2;
        }
        break;
    }
    op = tokenizer_token();
  }
  return f1;
}
示例#15
0
//static int relation(void)
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;
}
示例#16
0
/*---------------------------------------------------------------------------*/
void
tokenizer_next(void)
{

  if(tokenizer_finished()) {
    return;
  }

  DEBUG_PRINTF("tokenizer_next: %p\n", nextptr);
  ptr = nextptr;

  while(*ptr == ' ') {
    ++ptr;
  }
  current_token = get_next_token();

  if(current_token == TOKENIZER_REM) {
      while(!(*nextptr == '\n' || tokenizer_finished())) {
        ++nextptr;
      }
      if(*nextptr == '\n') {
        ++nextptr;
      }
      tokenizer_next();
  }

  DEBUG_PRINTF("tokenizer_next: '%s' %d\n", ptr, current_token);
  return;
}
示例#17
0
/*---------------------------------------------------------------------------*/
static void expr(struct typevalue *r1)
{
  struct typevalue r2;
  int op;

  relation(r1);
  op = current_token;
  DEBUG_PRINTF("logicrelation: token %d\n", op);
  /* FIXME: unclear the while is correct here. It's not correct in most
     BASIC to write  A > B > C, rather relations should be two part linked
     with logic */
  while(op == TOKENIZER_AND ||
       op == TOKENIZER_OR) {
    tokenizer_next();
    relation(&r2);
    /* No type checks needed on relations */
    DEBUG_PRINTF("logicrelation: %d %d %d\n", r1->d.i, op, r2.d.i);
    switch(op) {
      case TOKENIZER_AND:
        r1->d.i = r1->d.i & r2.d.i;
        break;
      case TOKENIZER_OR:
        r1->d.i = r1->d.i | r2.d.i;
        break;
    }
    op = current_token;
  }
  r1->type = TYPE_INTEGER;
}
示例#18
0
Phrase *
phrase_from_string (const gchar *str)
{
    Tokenizer *tok;
    gchar *term;
    Phrase *phrase;

    g_return_val_if_fail(str != NULL, NULL);

    if (index(str, '/') != NULL) {
        gchar **strs;
        guint idx;
        strs = g_strsplit(str, "/", 0);
        phrase = phrase_new();
        for (idx = 0; strs[idx] != NULL; idx++) {
            phrase_append(phrase, strs[idx]);
        }
        g_strfreev(strs);
    } else {
        tok = tokenizer_new(str);
        phrase = phrase_new();
        while(term = tokenizer_next(tok)){
            phrase_append_nocopy(phrase, term);
        }
        tokenizer_free(tok);
    }

    return phrase;
}
示例#19
0
/*---------------------------------------------------------------------------*/
static void term(struct typevalue *v)
{
  struct typevalue f2;
  int op;

  factor(v);
  op = current_token;
  DEBUG_PRINTF("term: token %d\n", op);
  while(op == TOKENIZER_ASTR ||
       op == TOKENIZER_SLASH ||
       op == TOKENIZER_MOD) {
    tokenizer_next();
    factor(&f2);
    typecheck_int(v);
    typecheck_int(&f2);
    DEBUG_PRINTF("term: %d %d %d\n", v->d.i, op, f2.d.i);
    switch(op) {
    case TOKENIZER_ASTR:
      v->d.i *= f2.d.i;
      break;
    case TOKENIZER_SLASH:
      if (f2.d.i == 0)
        ubasic_error(divzero);
      v->d.i /= f2.d.i;
      break;
    case TOKENIZER_MOD:
      if (f2.d.i == 0)
        ubasic_error(divzero);
      v->d.i %= f2.d.i;
      break;
    }
    op = current_token;
  }
  DEBUG_PRINTF("term: %d\n", v->d.i);
}
示例#20
0
//static void gosub_statement(void)
void gosub_statement(void)
{
	int linenum,nextnum;
	char *tmpptr, *tmpnextptr;
	
	accept(TOKENIZER_GOSUB);
	linenum = tokenizer_num();
	accept(TOKENIZER_NUMBER);
	tmpptr = ptr;
	tmpnextptr = nextptr;
	while(tokenizer_token() != TOKENIZER_CR &&
		tokenizer_token() != TOKENIZER_ENDOFINPUT){
		tokenizer_next();
	}
	accept(TOKENIZER_CR);
	nextnum = tokenizer_num();
	ptr = tmpptr;
	nextptr = tmpnextptr;
	if(gosub_stack_ptr < MAX_GOSUB_STACK_DEPTH) {
		gosub_stack[gosub_stack_ptr] = nextnum;
		gosub_stack_ptr++;
		jump_linenum(linenum);
	}else{
	}
}
示例#21
0
文件: tokenizer.c 项目: pelrun/CHDK
/*---------------------------------------------------------------------------*/
void
tokenizer_init(const char *program)
{
  ptr = program;
  current_line = 1;
  current_token = get_next_token();
  while (current_token==TOKENIZER_CR && !tokenizer_finished()) tokenizer_next();
}
示例#22
0
/*---------------------------------------------------------------------------*/
static void
jump_linenum_slow(int linenum)
{
  tokenizer_init(program_ptr);
  while(tokenizer_num() != linenum) {
    do {
      do {
        tokenizer_next();
      } while(current_token != TOKENIZER_CR &&
          current_token != TOKENIZER_ENDOFINPUT);
      if(current_token == TOKENIZER_CR) {
        tokenizer_next();
      }
    } while(current_token != TOKENIZER_NUMBER);
    DEBUG_PRINTF("jump_linenum_slow: Found line %d\n", tokenizer_num());
  }
}
示例#23
0
//static void comment_accept(void)
void comment_accept(void)
{
	int op;
	op = tokenizer_token();
	while((TOKENIZER_CR != op)&&(TOKENIZER_ENDOFINPUT != op)){
		tokenizer_next();
		op = tokenizer_token();
	}
}
示例#24
0
static void input_statement(void)
{
  struct typevalue r;
  var_t v;
  char buf[129];
  uint8_t t;
  uint8_t first = 1;
  int l;
  
  t = current_token;
  if (t == TOKENIZER_STRING) {
    tokenizer_string_func(charout, NULL);
    tokenizer_next();
    t = current_token;
    accept_either(TOKENIZER_COMMA, TOKENIZER_SEMICOLON);
  } else {
    charout('?', NULL);
    charout(' ', NULL);
  }

  begin_input();
  /* Consider the single var allowed version of INPUT - it's saner for
     strings by far ? */
  do {
    int n = 0;
    struct typevalue s[MAX_SUBSCRIPT];
    if (!first)
      accept_either(TOKENIZER_COMMA, TOKENIZER_SEMICOLON);
    first = 0;
    t = current_token;
    v = tokenizer_variable_num();
    accept_either(TOKENIZER_INTVAR, TOKENIZER_STRINGVAR);
    if (current_token == TOKENIZER_LEFTPAREN)
      n = parse_subscripts(s);

    /* FIXME: this works for stdin but not files .. */
    if ((l = read(0, buf + 1, 128)) <= 0) {
      write(2, "EOF\n", 4);
      exit(1);
    }
    charreset();		/* Newline input so move to left */
    if (t == TOKENIZER_INTVAR) {
      r.type = TYPE_INTEGER;	/* For now */
      r.d.i = atoi(buf + 1);	/* FIXME: error checking */
    } else {
      /* Turn a C string into a BASIC one */
      r.type = TYPE_STRING;
      if (buf[l-1] == '\n')
        l--;
      *((uint8_t *)buf) = l;
      r.d.p = (uint8_t *)buf;
    }
    ubasic_set_variable(v, &r, n, s);
  } while(!statement_end());
  end_input();
}
示例#25
0
文件: ubasic.c 项目: CobooGuo/ubasic
/*---------------------------------------------------------------------------*/
static void
accept(int token)
{
  if(token != tokenizer_token()) {
    DEBUG_PRINTF("Token not what was expected (expected %d, got %d)\n",
                token, tokenizer_token());
    tokenizer_error_print();
    exit(1);
  }
  DEBUG_PRINTF("Expected %d, got it\n", token);
  tokenizer_next();
}
示例#26
0
/*---------------------------------------------------------------------------*/
static uint8_t accept_tok(uint8_t token)
{
  if(token != current_token) {
    DEBUG_PRINTF("Token not what was expected (expected %d, got %d)\n",
                token, current_token);
    tokenizer_error_print();
    exit(1);
  }
  DEBUG_PRINTF("Expected %d, got it\n", token);
  tokenizer_next();
  /* This saves lots of extra calls - return the new token */
  return current_token;
}
示例#27
0
//static void jump_linenum(int linenum)
void jump_linenum(int linenum)
{
	ptr = BASICBUF;
	nextptr = ptr;

	tokenizer_init(ptr);
	while(tokenizer_num() != linenum) {
		do {
			do {
				tokenizer_next();
			} while(tokenizer_token() != TOKENIZER_CR &&
					tokenizer_token() != TOKENIZER_ENDOFINPUT);
			if(tokenizer_token() == TOKENIZER_CR) {
				tokenizer_next();
			}
			if(tokenizer_token() == TOKENIZER_ENDOFINPUT){
				ended = 1;
				return;
			}
		} while(tokenizer_token() != TOKENIZER_NUMBER);
	}
}
示例#28
0
static int search_cvars(const char *var_name) {
	int idx=0;
	// Variablenname in Tabelle suchen
#if USE_PROGMEM
	while((int *)pgm_read_word(&cvars[idx].pvar) != NULL &&
	      strncasecmp_P(var_name, cvars[idx].var_name, MAX_NAME_LEN)) {
    	idx++;
    }
#else
	while(cvars[idx].pvar != NULL &&
	      strncasecmp(cvars[idx].var_name, var_name, MAX_NAME_LEN)) {
    	idx++;
    }
#endif
    // keinen Tabelleneintrag gefunden!
#if USE_PROGMEM
    if ((int *)pgm_read_word(&cvars[idx].pvar) == NULL) {
#else
    if (cvars[idx].pvar == NULL) {
#endif
    	tokenizer_error_print(current_linenum, UNKNOWN_CVAR_NAME);
		ubasic_break();
    }
	return idx;
}

void vpoke_statement(void) {
	int idx=0;
#if USE_PROGMEM
	int *var_temp;
#endif

	accept(TOKENIZER_VPOKE);
    accept(TOKENIZER_LEFTPAREN);
	// Variablenname ermitteln
	if(tokenizer_token() == TOKENIZER_STRING) {
		tokenizer_next();
	}
	idx=search_cvars(tokenizer_last_string_ptr());
	accept(TOKENIZER_RIGHTPAREN);
	accept(TOKENIZER_EQ);
#if USE_PROGMEM
	var_temp=(int *)pgm_read_word(&cvars[idx].pvar);
	*var_temp=expr();
#else
	*cvars[idx].pvar = expr();
#endif
	//tokenizer_next();
}
static void accept (int token)
{
  char string[10];
  if (token != tokenizer_token())
  {
    /* Token was unexpected. */
    to_string(string, sizeof string);
    dprintf("*vvtbi.c: unexpected `%s' "
      "near `%s', expected: `%s'\n",
      E_ERROR,
      vvtbi_token(tokenizer_token()),
      /* If empty, EOF! */
      ((strlen(string)) ? string : "EOF"),
      vvtbi_token(token));
  }
  tokenizer_next();
}
示例#30
0
/*---------------------------------------------------------------------------*/
static void mathexpr(struct typevalue *v)
{
  struct typevalue t2;
  int op;

  term(v);
  op = current_token;
  DEBUG_PRINTF("mathexpr: token %d\n", op);
  while(op == TOKENIZER_PLUS ||
       op == TOKENIZER_MINUS ||
       op == TOKENIZER_BAND ||
       op == TOKENIZER_BOR) {
    tokenizer_next();
    term(&t2);
    if (op != TOKENIZER_PLUS)
      typecheck_int(v);
    typecheck_same(v, &t2);
    DEBUG_PRINTF("mathexpr: %d %d %d\n", v->d.i, op, t2.d.i);
    switch(op) {
    case TOKENIZER_PLUS:
      if (v->type == TYPE_INTEGER)
        v->d.i += t2.d.i;
      else {
        uint8_t *p;
        uint8_t l = *v->d.p;
        p = string_temp(l + *t2.d.p);
        memcpy(p + 1, v->d.p + 1, l);
        memcpy(p + l + 1, t2.d.p + 1, *t2.d.p);
        v->d.p = p;
      }
      break;
    case TOKENIZER_MINUS:
      v->d.i -= t2.d.i;
      break;
    case TOKENIZER_BAND:
      v->d.i &= t2.d.i;
      break;
    case TOKENIZER_BOR:
      v->d.i |= t2.d.i;
      break;
    }
    op = current_token;
  }
  DEBUG_PRINTF("mathexpr: %d\n", v->d.i);
}