Beispiel #1
0
char *STRTOK_R(char *pStr, const char *pDelims, char **ppSave)
{
  if (!pStr)
    pStr = *ppSave;

  while (IsDelim(*pStr, pDelims))
    pStr++;

  if (!*pStr) {
    *ppSave = pStr;
    return NULL;
  }

  char *pToken = pStr;

  while (*pStr && !IsDelim(*pStr, pDelims))
    pStr++;

  if (*pStr)
    *pStr++ = 0;

  *ppSave = pStr;

  return pToken;
}
Beispiel #2
0
ItTokenizer::Token ItTokenizer::NextToken() {
    const char* cur = end;
    while('\0' != *cur && IsDelim(delim, *cur)) cur++;
    start = cur;
    while('\0' != *cur && !IsDelim(delim, *cur)) cur++;
    end = cur;
    return Token(start, end);
}
Beispiel #3
0
static inline Stroka GetFile(const Stroka& s) {
    const char* e = s.end();
    const char* b = s.begin();
    const char* c = e - 1;

    while (c != b && !IsDelim(*c)) {
        --c;
    }

    if (c != e && IsDelim(*c)) {
        ++c;
    }

    return Stroka(c, e - c);
}
Beispiel #4
0
// expected string: "content", returned string: content
ItTokenizer::Token ItTokenizer::ExpectStr(std::string& str) {
    const char* cur = end;
    while('\0' != *cur && IsDelim(delim, *cur)) cur++;
    const char *nstart = cur;

    if('\"' != *cur++) {
        char tokBuf[512] = { 0 };
        strncpy(tokBuf, nstart, 1);
        common.printf("ERROR - %s: ", this->name);
        common.printf("expecting STRING, got '%s'\n",
            tokBuf);
        Crash();
    }

    while('\0' != *cur) {
        if('\"' == *cur) {
            str = std::string(nstart + 1, cur - nstart - 1);

            start = nstart;
            end = cur + 1;
            return Token(start, end);
        }
        cur++;
    }

    char tokBuf[512] = { 0 };
    strncpy(tokBuf, nstart, 512);
    common.printf("ERROR - %s: ", this->name);
    common.printf("expecting STRING, got '%s'\n",
        tokBuf);
    Crash();

    // unreachable
    return Token(NULL, NULL);
}
Beispiel #5
0
static inline Stroka Fix(Stroka f) {
    if (!f.empty() && IsDelim(f[+f - 1])) {
        f.pop_back();
    }

    return f;
}
Beispiel #6
0
ItTokenizer::Token ItTokenizer::ExpectFloat(float &val) {
    const char* cur = end;
    while('\0' != *cur && IsDelim(delim, *cur)) cur++;
    const char *nstart = cur;

    bool    negative = false;
    float   num = 0;

    if('-' == *cur) {
        negative = true;
        cur++;
    }

    if(!isdigit(*cur)) {
        char tokBuf[512] = { 0 };
        strncpy(tokBuf, nstart, 1);
        common.printf("ERROR - %s: ", this->name);
        common.printf("expecting FLOAT, got '%s'\n",
            tokBuf);
        Crash();
    }

    while(isdigit(*cur)) {
        num *= 10.0f;
        num += *cur - '0';
        cur++;
    }

    if('.' == *cur) {
        cur++;

        float pow = 0.1f;
        while(isdigit(*cur)) {
            num += pow * (*cur - '0');
            pow /= 10.0f;
            cur++;
        }
    }

    if(negative) num *= -1;

    val = num;

    start = nstart;
    end = cur;

    return Token(start, end);
}
Beispiel #7
0
ItTokenizer::Token ItTokenizer::Expect(const char* name) {
    const char* cur = end;
    while('\0' != *cur && IsDelim(delim, *cur)) cur++;
    const char *nstart = cur, *nameCur = name;
    while('\0' != *nameCur) {
        if(*cur++ != *nameCur++) {
            char tokBuf[512] = { 0 };
            strncpy(tokBuf, nstart, cur - nstart);
            common.printf("ERROR - %s: ", this->name);
            common.printf("expecting '%s', got '%s'\n",
                name, tokBuf);
            Crash();
        }
    }
    start = nstart;
    end = cur;
    return Token(start, end);
}
Beispiel #8
0
ItTokenizer::Token ItTokenizer::ExpectInt(int& val) {
    const char* cur = end;
    while('\0' != *cur && IsDelim(delim, *cur)) cur++;
    const char *nstart = cur;

    bool    negative = false;
    int     num = 0;
    int     arity = 1;

    if('-' == *cur) {
        negative = true;
        cur++;
    }

    if(!isdigit(*cur)) {
        char tokBuf[512] = { 0 };
        strncpy(tokBuf, nstart, 1);
        common.printf("ERROR - %s: ", this->name);
        common.printf("expecting INT, got '%s'\n",
            tokBuf);
        Crash();
    }

    while(isdigit(*cur)) {
        num *= 10;
        num += *cur - '0';
        cur++;
    }

    if(negative) num *= -1;

    val = num;

    start = nstart;
    end = cur;

    return Token(start, end);
}
Beispiel #9
0
void op_extract()
{
 /* Stack:

     |=============================|=============================|
     |            BEFORE           |           AFTER             |
     |=============================|=============================|
 top |  Subvalue number            | Substring                   |
     |-----------------------------|-----------------------------| 
     |  Value number               |                             |
     |-----------------------------|-----------------------------| 
     |  Field number               |                             |
     |-----------------------------|-----------------------------| 
     |  Source string              |                             |
     |=============================|=============================|
 */

 DESCRIPTOR * field_descr;      /* Position descriptor */
 DESCRIPTOR * value_descr;      /* Position descriptor */
 DESCRIPTOR * subvalue_descr;   /* Position descriptor */
 DESCRIPTOR * src_descr;        /* Source string */
 DESCRIPTOR result_descr;       /* Result string */
 long int field;
 long int value;
 long int subvalue;
 short int offset;
 STRING_CHUNK * str_hdr;
 short int bytes_remaining;
 short int len;
 char * p;
 char * q;
 bool end_on_value_mark;
 bool end_on_subvalue_mark;
 register char c;


 subvalue_descr = e_stack - 1;
 value_descr = e_stack - 2;
 field_descr = e_stack - 3;

 GetInt(subvalue_descr);
 subvalue = subvalue_descr->data.value;

 GetInt(value_descr);
 value = value_descr->data.value;

 GetInt(field_descr);
 field = field_descr->data.value;

 k_pop(3);

 /* Set up a string descriptor on our C stack to receive the result */

 InitDescr(&result_descr, STRING);
 result_descr.data.str.saddr = NULL;
 ts_init(&result_descr.data.str.saddr, 32);

 if (field <= 0)      /* Field zero or negative  -  Return null string */
  {
   goto done;
  }
 else if (value == 0) /* Extracting field */
  {
   end_on_value_mark = FALSE;
   end_on_subvalue_mark = FALSE;
   value = 1;
   subvalue = 1;
  }
 else if (subvalue == 0) /* Extracting value */
  {
   end_on_value_mark = TRUE;
   end_on_subvalue_mark = FALSE;
   subvalue = 1;
  }
 else /* Extracting subvalue */
  {
   end_on_value_mark = TRUE;
   end_on_subvalue_mark = TRUE;
  }

 src_descr = e_stack - 1;
 k_get_string(src_descr);
 str_hdr = src_descr->data.str.saddr;

 if (find_item(str_hdr, field, value, subvalue, &str_hdr, &offset))
  {
   if (str_hdr == NULL) goto done;

   p = str_hdr->data + offset;
   bytes_remaining = str_hdr->bytes - offset;

   while(1)
    {
     /* Is there any data left in this chunk? */

     if (bytes_remaining)
      {
       /* Look for delimiter in the current chunk */

       for (q = p; bytes_remaining-- > 0; q++)
        {
         c = *q;
         if ((IsDelim(c))
          && ((c == FIELD_MARK)
             || ((c == VALUE_MARK) && end_on_value_mark)
             || ((c == SUBVALUE_MARK) && end_on_subvalue_mark)))
          {
           /* Copy up to mark */

           len = q - p;
           if (len > 0) ts_copy(p, len);

           goto done;
          }
        }

       /* Copy remainder of this chunk (must be at least one byte) */

       ts_copy(p, q - p);
      }

     if ((str_hdr = str_hdr->next) == NULL) break;

     p = str_hdr->data;
     bytes_remaining = str_hdr->bytes;
    }
  }

done:
 ts_terminate();

 k_dismiss();   /* Dismiss source string ADDR */

 *(e_stack++) = result_descr;
}
Beispiel #10
0
Private void rdi(
   DESCRIPTOR * src_descr,        /* Source string */
   long int field,
   long int value,
   long int subvalue,
   short int mode,
   DESCRIPTOR * new_descr,        /* Replacement / insertion string */
   DESCRIPTOR * result_descr,     /* Resultant string */
   bool compatible)               /* Append style ($MODE COMPATIBLE.APPEND) */
{
 long int f, v, sv;
 STRING_CHUNK * str_hdr;
 short int bytes_remaining;
 STRING_CHUNK * new_str;
 short int len;
 char * p;
 bool done;
 char c;
 char mark;
 bool mark_skipped = FALSE;
 bool end_on_value_mark;
 bool end_on_subvalue_mark;
 bool item_found;
 char last_char = '\0';


 str_hdr = src_descr->data.str.saddr;

 /* Set up a string descriptor to receive the result */

 InitDescr(result_descr, STRING);
 result_descr->data.str.saddr = NULL;
 ts_init(&(result_descr->data.str.saddr), (str_hdr == NULL)?64:str_hdr->string_len);


 if (field == 0) field = 1;

 if (value == 0) /* <n, 0, 0> */
  {
   end_on_value_mark = FALSE;
   end_on_subvalue_mark = FALSE;
   value = 1;
   subvalue = 1;
   mark = FIELD_MARK;
  }
 else if (subvalue == 0) /* <n, n, 0> */
  {
   end_on_value_mark = TRUE;
   end_on_subvalue_mark = FALSE;
   subvalue = 1;
   mark = VALUE_MARK;
  }
 else /* <n, n, n> */
  {
   end_on_value_mark = TRUE;
   end_on_subvalue_mark = TRUE;
   mark = SUBVALUE_MARK;
  }

 f = 1; v = 1; sv = 1;   /* Current position */
 bytes_remaining = 0;    /* For null string path */

 /* Copy to start of selected item */

 if ((field == 1) && (value == 1) && (subvalue == 1))
  {  /* <1,0,0> or <1,1,0> or <1,1,1> */
   if (str_hdr != NULL)
    {
     p = str_hdr->data;
     bytes_remaining = str_hdr->bytes;
    }
   item_found = TRUE;
   goto found; 
  }

 /* Walk the string to the desired item */

 if (str_hdr != NULL)
  {
   do {
       p = str_hdr->data;
       bytes_remaining = str_hdr->bytes;

       do {
           c = *p;
           if (IsDelim(c))
            {
             switch(c)
              {
               case FIELD_MARK:
                  if (f == field) goto not_found; /* No such value or subvalue */
                  f++;
                  v = 1;
                  sv = 1;
                  break;

               case VALUE_MARK:
                  if ((f == field) && (v == value))
                   {
                    goto not_found; /* No such subvalue */
                   }
                  v++;
                  sv = 1;
                  break;  
  
               case SUBVALUE_MARK:
                  sv++;
                  break;
              }

             if ((f == field) && (v == value) && (sv == subvalue))
              {
               p++;
               bytes_remaining--;
               item_found = TRUE;
               goto found; /* At start position */
              }
            }
           last_char = c;
           p++;
          } while(--bytes_remaining);

       /* Copy all of source chunk just searched */
  
       ts_copy(str_hdr->data, str_hdr->bytes);
      } while((str_hdr = str_hdr->next) != NULL);
  }
      
 /* We have reached the end of the string without finding the field we
    were looking for.                                                  */


not_found:
          
found:

 if (str_hdr != NULL) /* Not run off end of string */
  {
   /* Copy up to current position in source chunk */

   len = p - str_hdr->data;

   if ((mode == DYN_DELETE) && (len > 0) && (c == mark)) /* Don't copy this mark */
    {
     mark_skipped = TRUE;
     len--;
    }

   if (len > 0) ts_copy(str_hdr->data, len);
  
  /* Skip old data if we are doing REPLACE or DELETE */
  
   if (item_found)
    {
     switch(mode)
      {
       case DYN_REPLACE:
       case DYN_DELETE:
          done = FALSE;

          /* Skip old item */
    
          do {
              /* Is there any data left in this chunk? */
    
              if (bytes_remaining > 0)
               {
                /* Look for delimiter in the current chunk */
    
                do {
                    c = *p;
                    if ((IsDelim(c))
                     && ((c == FIELD_MARK)
                        || ((c == VALUE_MARK) && end_on_value_mark)
                        || ((c == SUBVALUE_MARK) && end_on_subvalue_mark)))
                     {
                      done = TRUE;
                      break;
                     }
                    p++;
                   } while(--bytes_remaining);
               }

              if (!done) /* Find next chunk */
               {
                if (str_hdr->next == NULL) done = TRUE;
                else
                 {
                  str_hdr = str_hdr->next;
                  p = str_hdr->data;
                  bytes_remaining = str_hdr->bytes;
                 }
               }
             } while(!done);
  
          if ((mode == DYN_DELETE) && !mark_skipped && (c == mark))
           {
            /* Skip the mark too */
            p++;
            bytes_remaining--;
           }
          break;
      }
    }
  }

 /* Insert new data for REPLACE or INSERT */
 
 switch(mode)
  {
   case DYN_REPLACE:
   case DYN_INSERT:
      /* We may not be at the desired position. For example, if we try to
         insert <3,2,2> we might not have the necessary number of fields,
         values or subvalues to get to this position. We must insert marks
         to get us to the right position.                                  */

      if (result_descr->data.str.saddr != NULL) /* Not at start of string */
       {
        if (field < 0)
         {
          if (compatible && last_char == FIELD_MARK)
           {
            f = 1;       /* Kill mark insertion */
            field = 1;
           }
          else
           {
            field = f + 1; /* Insert a single field mark */
           }
          v = 1;
          sv = 1;
         }
        else if (value < 0)
         {
          if ((field != f)                /* No mark if adding new field... */
           || (last_char == FIELD_MARK)   /* ... or at start of a field */
           || (compatible && last_char == VALUE_MARK))
           {
            v = 1;        /* 0222 Set both to one to kill mark insertion */
            value = 1;
           }
          else value = v + 1;
          sv = 1;
         }
        else if (subvalue < 0)
         {
          if ((field != f)                /* No mark if adding new field... */
           || (value != v)                /* ...or adding new value... */
           || (last_char == FIELD_MARK)   /* ...or at start of a field... */
           || (last_char == VALUE_MARK)   /* ...or at start of a value */
           || (compatible && last_char == SUBVALUE_MARK))
           {
            sv = 1;       /* 0222 Set both to one to kill mark insertion */
            subvalue = 1;
           }
          else subvalue = sv + 1;
         }
       }

      while(f < field)
       {
        ts_copy_byte(FIELD_MARK);
        f++;
        v = 1;
        sv = 1;
       }

      while(v < value)
       {
        ts_copy_byte(VALUE_MARK);
        v++;
        sv = 1;
       }

      while(sv < subvalue)
       {
        ts_copy_byte(SUBVALUE_MARK);
        sv++;
       }

      /* Insert replacement item */
      
      for (new_str = new_descr->data.str.saddr;
           new_str != NULL;
           new_str = new_str->next)
       {
        ts_copy(new_str->data, new_str->bytes);
       }

      /* For insert mode, if we are not at the end of the source string and
         the next character of the source string is not a mark we must
         insert a mark to delimit the new data from the following item.     */

      if ((mode == DYN_INSERT) && (str_hdr != NULL))
       {
        if (bytes_remaining == 0) /* Mark was at end of chunk */
         {
          if ((str_hdr = str_hdr->next) == NULL) goto no_mark_required;
          p = str_hdr->data;
          bytes_remaining = str_hdr->bytes;
         }


        if ((!IsDelim(*p)) || (*p <= mark)) ts_copy_byte(mark);
       }
no_mark_required:     
      break;
  }

 /* Copy remainder of source string */

 if (str_hdr != NULL)
  { 
   /* Is there any data left in this chunk? */

   if (bytes_remaining > 0) ts_copy(p, bytes_remaining);

   /* Copy any remaining chunks */

   while((str_hdr = str_hdr->next) != NULL)
    {
     ts_copy(str_hdr->data, str_hdr->bytes);
    }
  }

 ts_terminate();
}
Beispiel #11
0
bool find_item(
   STRING_CHUNK * str,
   long int field,
   long int value,
   long int subvalue,
   STRING_CHUNK ** chunk,
   short int * offset)
{
 long int f, v, sv;
 STRING_CHUNK * first_chunk;
 short int bytes_remaining;
 char * p;
 char * q;
 register char c;
 long int hint_field;
 long int hint_offset;
 long int new_hint_offset = -1;
 long int skip;

 if ((field == 1) && (value == 1) && (subvalue == 1))
  {  /* <1,0,0> or <1,1,0> or <1,1,1> */
   *chunk = str;
   *offset = 0;

   if (str != NULL)
    {
     /* Set hint.  This is a bit unfortunate but it simplifies code elsewhere
        as all calls to find_item() that return true must set the hint to
        address the item that was found. Having a hint for the start of the
        string is somewhat unnecessary!                                      */

     first_chunk = str;
     first_chunk->field = 1;
     first_chunk->offset = 0;
    }
   return TRUE;
  }

 if (str == NULL) return FALSE;

 /* Walk the string to the desired item */

 first_chunk = str;

 hint_field = str->field;
 if ((hint_field)              /* Hint present... */
  && (hint_field <= field))    /* ...in suitable field */
  {
   /* We have a usable hint to aid location of the desired item */

   hint_offset = str->offset;
   skip = hint_offset;

   while(skip >= str->bytes)
    {
     skip -= str->bytes;
     if (str->next == NULL) /* Hint points to byte following end of string */
      {
       if ((hint_field == field) /* Right field */
        && (value == 1)          /* Right value */
        && (subvalue == 1))      /* Right subvalue */
        {
         *chunk = str;
         *offset = str->bytes;
         return TRUE;
        }

       return FALSE;
      }
     str = str->next;
    } 

   hint_offset -= skip;
   p = str->data + skip;
   bytes_remaining = (short int)(str->bytes - skip);
   f = hint_field;
  }
 else            /* No hint available */
  {
   hint_offset = 0;
   p = str->data;
   bytes_remaining = str->bytes;
   f = 1;
  }

 v = 1;
 sv = 1;
 

 if (f < field)
  {
   v = 1;
   do {
       while(bytes_remaining)
        {
         q = (char *)memchr(p, FIELD_MARK, bytes_remaining);
         if (q == NULL) break;  /* No mark in this chunk */
     
         bytes_remaining -= (q - p) + 1;
         p = q + 1;                      /* Position after mark */
         if (++f == field) goto field_found;
        }

       if (str->next == NULL) return FALSE;

       hint_offset += str->bytes;
       str = str->next;
       p = str->data;
       bytes_remaining = str->bytes;
      } while(1);
  }

field_found:
 new_hint_offset = hint_offset + p - str->data;

 if ((value == v) && (subvalue == 1)) /* At start position */
  {
   goto exit_find_item;
  }

 /* Scan for value / subvalue */

 while(1)
  {
   while(bytes_remaining-- > 0)
    {
     c = *(p++);
     if (IsDelim(c))
      {
       switch(c)
        {
         case FIELD_MARK:
            return FALSE; /* No such value or subvalue */

         case VALUE_MARK:
            if (++v > value) return FALSE; /* No such subvalue */
            sv = 1;
            break;  

         case SUBVALUE_MARK:
            sv++;
            break;
        }

       if ((v == value) && (sv == subvalue))   /* At start position */
        {
         goto exit_find_item;
        }
      }
    }

   /* Advance to next chunk */

   if (str->next == NULL) break;

   str = str->next;
   p = str->data;
   bytes_remaining = str->bytes;
  }

 return FALSE;

exit_find_item:
 *chunk = str;
 *offset = p - str->data;

 if (new_hint_offset >= 0)
  {
   first_chunk->field = field;
   first_chunk->offset = new_hint_offset;
  }

 return TRUE;
}
bool TParser::GetToken(void)
{
   *curToken = '\0';
   
   while(expr[pos]==' ') pos++;
   
   if(expr[pos]=='\0')
   {
      curToken[0] = '\0';
      typToken = PARSER_END;
      return true;
   }
   else if(IsDelim())
   {
      curToken[0] = expr[pos++];
      curToken[1] = '\0';
      switch(*curToken)
      {
         case '+': typToken = PARSER_PLUS; return true;
         case '-': typToken = PARSER_MINUS; return true;
         case '*': typToken = PARSER_MULTIPLY; return true;
         case '/': typToken = PARSER_DIVIDE; return true;
         case '%': typToken = PARSER_PERCENT; return true;
         case '^': typToken = PARSER_POWER; return true;
         case '[':
         case '(': typToken = PARSER_L_BRACKET; return true;
         case ']':
         case ')': typToken = PARSER_R_BRACKET; return true;
      }
   }
   else if(IsLetter())
   {
      int i=0;
      while(IsLetter()) curToken[i++] = expr[pos++];
      curToken[i] = '\0';

      int len = strlen(curToken);
      for(i=0; i<len; i++)
         if(curToken[i]>='A' && curToken[i]<='Z')
            curToken[i] += 'a' - 'A';

      if(!strcmp(curToken, "x"))           { typToken = PARSER_X; return true; }
      else if(!strcmp(curToken, "pi"))     { typToken = PARSER_PI; return true; }
      else if(!strcmp(curToken, "e"))      { typToken = PARSER_E; return true; }
      else if(!strcmp(curToken, "sin"))    { typToken = PARSER_SIN; return true; }
      else if(!strcmp(curToken, "cos"))    { typToken = PARSER_COS; return true; }
      else if(!strcmp(curToken, "tg"))     { typToken = PARSER_TG; return true; }
      else if(!strcmp(curToken, "ctg"))    { typToken = PARSER_CTG; return true; }
      else if(!strcmp(curToken, "arcsin")) { typToken = PARSER_ARCSIN; return true; }
      else if(!strcmp(curToken, "arccos")) { typToken = PARSER_ARCCOS; return true; }
      else if(!strcmp(curToken, "arctg"))  { typToken = PARSER_ARCTG; return true; }
      else if(!strcmp(curToken, "arcctg")) { typToken = PARSER_ARCCTG; return true; }
      else if(!strcmp(curToken, "sh"))     { typToken = PARSER_SH; return true; }
      else if(!strcmp(curToken, "ch"))     { typToken = PARSER_CH; return true; }
      else if(!strcmp(curToken, "th"))     { typToken = PARSER_TH; return true; }
      else if(!strcmp(curToken, "cth"))    { typToken = PARSER_CTH; return true; }
      else if(!strcmp(curToken, "exp"))    { typToken = PARSER_EXP; return true; }
      else if(!strcmp(curToken, "lg"))     { typToken = PARSER_LG; return true; }
      else if(!strcmp(curToken, "ln"))     { typToken = PARSER_LN; return true; }
      else if(!strcmp(curToken, "sqrt"))   { typToken = PARSER_SQRT; return true; }
      else SendError(0);
   }
   else if(IsDigit() || IsPoint())
   {
      int i=0;
      while(IsDigit()) curToken[i++] = expr[pos++];
      if(IsPoint())
      {
         curToken[i++] = expr[pos++];
         while(IsDigit()) curToken[i++] = expr[pos++];
      }
      curToken[i] = '\0';
      typToken = PARSER_NUMBER;
      return true;
   }
   else
   {
      curToken[0] = expr[pos++];
      curToken[1] = '\0';
      SendError(1);
   }

   return false;
}      
bool TParser::GetToken()
{
   curToken = _T("");
   
   if(pos >= expr.GetLength())
   {
      curToken = _T("");
      typToken = PARSER_END;
      return true;
   }

   while(IsSpace()) pos++;

   if(IsDelim())
   {
      curToken = expr[pos++];
      switch(curToken[0])
      {
         case _T('+'): typToken = PARSER_PLUS; return true;
         case _T('-'): typToken = PARSER_MINUS; return true;
         case _T('*'): typToken = PARSER_MULTIPLY; return true;
         case _T('/'): typToken = PARSER_DIVIDE; return true;
         case _T('%'): typToken = PARSER_PERCENT; return true;
         case _T('^'): typToken = PARSER_POWER; return true;
         case _T('['):
         case _T('('): typToken = PARSER_L_BRACKET; return true;
         case _T(']'):
         case _T(')'): typToken = PARSER_R_BRACKET; return true;
      }
   }
   else if(IsComma())
   {
	   curToken = expr[pos++];
	   typToken = PARSER_COMMA;
	   return true;
   }
   else if(IsLetter())
   {
      int i=0;
	  curToken = _T("");
      while(IsLetter() || IsDigit()) curToken += expr[pos++];

	  curToken.MakeLower();

      if(curToken == _T("pi"))			{ typToken = PARSER_PI; return true; }
      else if(curToken == _T("e"))      { typToken = PARSER_E; return true; }
      else if(curToken == _T("sin"))    { typToken = PARSER_SIN; return true; }
      else if(curToken == _T("cos"))    { typToken = PARSER_COS; return true; }
      else if(curToken == _T("tg"))     { typToken = PARSER_TG; return true; }
      else if(curToken == _T("ctg"))    { typToken = PARSER_CTG; return true; }
      else if(curToken == _T("arcsin")) { typToken = PARSER_ARCSIN; return true; }
      else if(curToken == _T("arccos")) { typToken = PARSER_ARCCOS; return true; }
      else if(curToken == _T("arctg"))  { typToken = PARSER_ARCTG; return true; }
      else if(curToken == _T("arcctg")) { typToken = PARSER_ARCCTG; return true; }
      else if(curToken == _T("sh"))     { typToken = PARSER_SH; return true; }
      else if(curToken == _T("ch"))     { typToken = PARSER_CH; return true; }
      else if(curToken == _T("th"))     { typToken = PARSER_TH; return true; }
      else if(curToken == _T("cth"))    { typToken = PARSER_CTH; return true; }
      else if(curToken == _T("exp"))    { typToken = PARSER_EXP; return true; }
      else if(curToken == _T("lg"))     { typToken = PARSER_LG; return true; }
      else if(curToken == _T("ln"))     { typToken = PARSER_LN; return true; }
      else if(curToken == _T("sqrt"))   { typToken = PARSER_SQRT; return true; }
	  else if(curToken == _T("abs"))	{ typToken = PARSER_ABS; return true; }

	  else if(curToken == _T("min"))    { typToken = PARSER_MIN; return true; }
	  else if(curToken == _T("max"))    { typToken = PARSER_MAX; return true; }
	  else if(curToken == _T("atan2"))  { typToken = PARSER_ATAN2; return true; }

	  else if(curToken == _T("if"))     { typToken = PARSER_IF; return true; }
	  
	  else if(curToken == _T("left"))   { typToken = PARSER_GUIDE; return true; }
  	  else if(curToken == _T("right"))  { typToken = PARSER_GUIDE; return true; }
  	  else if(curToken == _T("top"))    { typToken = PARSER_GUIDE; return true; }
  	  else if(curToken == _T("bottom")) { typToken = PARSER_GUIDE; return true; }
  	  else if(curToken == _T("width"))  { typToken = PARSER_GUIDE; return true; }
  	  else if(curToken == _T("height")) { typToken = PARSER_GUIDE; return true; }
      else SendError(0);
   }
   else if(IsAdjust())
   {
      int i=0;
	  curToken = _T("");
      while((!IsSpace())&&(!IsDelim())) curToken += expr[pos++];
	  
	  typToken = PARSER_ADJUST;
	  return true;
   }
   else if(IsGuide())
   {
      int i=0;
	  curToken = _T("");
      while((!IsSpace())&&(!IsDelim())) curToken += expr[pos++];
	  
	  typToken = PARSER_GUIDE;
	  return true;
   }
   else if(IsDigit() || IsPoint())
   {
      int i=0;
	  curToken = _T("");
      while(IsDigit()) curToken += expr[pos++];
      if(IsPoint())
      {
         curToken += expr[pos++];
         while(IsDigit()) curToken += expr[pos++];
      }
      typToken = PARSER_NUMBER;
      return true;
   }
   else
   {
      curToken = expr[pos++];
      SendError(1);
   }

   return false;
}      
void CUrlRichEditCtrl::ParseAndFormatText(BOOL bForceReformat)
{
	KillTimer(TIMER_REPARSE);
	AF_NOREENTRANT // prevent reentrancy
		
	// parse the control content
	CString sText;
	GetWindowText(sText);
	
	// richedit2 uses '\r\n' whereas richedit uses just '\n'
	if (!CWinClasses::IsClass(*this, WC_RICHEDIT))
		sText.Replace(_T("\r\n"), _T("\n"));
	
	// parse the text into an array of URLPOS
	CUrlArray aUrls;
	LPCTSTR szText = sText;
	BOOL bPrevDelim = TRUE;
	int nPos = 0;
	BOOL bBracedFile = FALSE;
	
	while (*szText) 
	{
		// if nChar < 0 then its a multibyte char and can't be part
		// of a url, so we bump the text buffer by 2 but the pos by 1
#ifndef _UNICODE
		TCHAR nChar = *szText;
		
		if (IsDBCSLeadByte(nChar))
		{
			szText++; 
			szText++;
			nPos++;
			continue;
		}
#endif
		// if the previous item was not a delimiter then there's no
		// point checking for a protocol match so we just update the
		// value of bPrevDelim for the current char
		if (!bPrevDelim)
		{
			bPrevDelim = IsDelim(szText);
			szText++;
			nPos++;
			continue;
		}
		// if the current char is a delim then this can't be the start
		// of a url either
		else if (IsDelim(szText))
		{
			bPrevDelim = TRUE;
			szText++;
			nPos++;
			continue;
		}
		
		// now check for a protocol
		int nProt = MatchProtocol(szText);
		
		// if no match then increment pos and go to next char
		if (nProt == -1)
		{
			bPrevDelim = FALSE;
			szText++;
			nPos++;
			continue;
		}
		
		// check for braces (<...>)
		if (nPos > 0)
			bBracedFile = (szText[-1] == '<');
		else
			bBracedFile = FALSE;
		
		// find the end of the url (URLDELIMS)
		int nLen = 0;
		LPCTSTR szStart = szText;
		
		if (bBracedFile)
		{
			while (*szText && *szText != '>')
			{
				szText++;
				nLen++;
			}
		}
		else
		{
			while (!IsDelim(szText))
			{
				szText++;
				nLen++;
			}
		}
		
		bPrevDelim = TRUE;
		
		// save the result
		URLITEM urli;
		urli.cr.cpMin = nPos;
		urli.cr.cpMax = urli.cr.cpMin + nLen;
		nPos += nLen;
		
		// make sure the url does not end in a punctuation mark
		while (ENDPUNCTUATION.Find(szStart[nLen - 1]) != -1)
		{
			nLen--;
			urli.cr.cpMax--;
		}
		
		// Only save if the link is more than just the protocol
		if (nLen > m_aProtocols[nProt].sProtocol.GetLength())
		{
			urli.sUrl = CString(szStart, nLen);
			urli.bWantNotify = m_aProtocols[nProt].bWantNotify;
			
			InsertInOrder(urli, aUrls);
		}
	}
	
	// compare aUrls with m_aUrls to see if anything has changed
	BOOL bReformat = !sText.IsEmpty() && (bForceReformat || !UrlsMatch(aUrls));
	
	// then overwrite (always)	
	m_aUrls.Copy(aUrls);
	
	if (bReformat)
	{
		BOOL bVisible = IsWindowVisible();
		CRePauseUndo rep(*this);
		
		if (bVisible)
			SetRedraw(FALSE);
		
		// save current selection
		CHARRANGE crSel;
		GetSel(crSel);
		
		// and first line
		int nFirstLine = GetFirstVisibleLine();
		
		// save/reset event mask
		DWORD dwEventMask = SetEventMask(0);
		
		// retrieve default character attribs
		CHARFORMAT cf;
		cf.cbSize = sizeof(cf);
		cf.dwMask = CFM_LINK;
		
		// format urls
		int nUrls = aUrls.GetSize();
		CHARRANGE cr = { 0, 0 };
		
		for (int nUrl = 0; nUrl < nUrls; nUrl++)
		{
			// clear formatting from the end of the previous
			// url to the start of this url
			cr.cpMax = aUrls[nUrl].cr.cpMin;
			cf.dwEffects = 0;
			
			SetSel(cr);
			SetSelectionCharFormat(cf);
			
			// update for next url
			cr.cpMin = aUrls[nUrl].cr.cpMax;
			
			// then format url
			cf.dwEffects = CFM_LINK;
			
			SetSel(aUrls[nUrl].cr);
			SetSelectionCharFormat(cf);
		}	
		
		// clear formatting for whatever's left
		cr.cpMax = -1;
		cf.dwEffects = 0;
		
		SetSel(cr);
		SetSelectionCharFormat(cf);
		
		// restore selection
		SetSel(crSel);
		
		// and first line
		SetFirstVisibleLine(nFirstLine);
		
		// restore event mask
		SetEventMask(dwEventMask);

		if (bVisible)
		{
			SetRedraw(TRUE);
			Invalidate(FALSE);
		}
	}
}