⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tokens.cpp

📁 UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh
💻 CPP
📖 第 1 页 / 共 2 页
字号:

bool TokenStream::look_ahead_more(char ch)
{
 char *p = P;
 while (true) {
   while (*p && isspace(*p)) p++;
   if (*p) {
     return (*p == ch);
   }
   grab_next();
 }
}

bool TokenStream::fetch_line()
{
 int len;
 bool continuation = true;
 *buff = '\0';
 while (true) { // looking for non-blank, non-preprocessor lines
 set_str(buff);
 do {
     //...if we have run out of file, close and try to continue
     if (!inf || inf->eof()) {
         if(!close()){
            set_str(buff);
            return false;  // we have run out of open files
         // restored old file;  can continue
         }
     }
     do_prompt();   // really only need to call this when in interactive mode...
#ifndef _USE_READLINE
     inf->getline(lbuff,LINESIZE); 
#else
         if (inf != con_in) inf->getline(lbuff,LINESIZE);
         else {
            char *pl = readline(get_prompt_buffer());
            if (pl == NULL) return false; // *fix 1.2.2 (Dean) Stopping process with ctrl-D
            strcpy(lbuff,pl);
            free(pl);
            add_history(lbuff);
         }
#endif
// *fix 1.1.0 spaces after \ messes with the preprocessor's little mind!
     char *endp = lbuff + strlen(lbuff) - 1;
	 while (*endp && isspace(*endp)) --endp;
     continuation = (*endp == '\\'); 
//     if (continuation) *endp = '\0';  // lop off '\'
     if (continuation) { *(endp+1) = '\0';  *endp = '\n'; }
     strcat(buff,lbuff);  
	 line++;
 } while (continuation);

 start = P = start_P = buff; 
 while(isspace(*P)) P++;
 if (*P == 0) continue;  // can ignore empty lines!
 if (*P == '#' && ! in_comment) { 
     m_C_str = false;
     P++;
     try {
       if (!do_prepro_directive(*this)) {
          close(); 
          m_C_str = true;
          return false; // bail out!
       }
     } catch(string msg) {
 // *fix 1.2.7 fatal errors must stop parsing, unless in interactive mode.
 // *fix 1.2.8 true, but that isn't the same as 'inf != con_in'!  
 //  is_interactive_mode() is a virtual function overriden by UCTokenStream.
       if (! is_interactive_mode()) return false;
     }
     m_C_str = true;
 }
 else
 if (! m_skip) {
   // ensure that there's a final line feed!    
    if (m_line_feed) { 
      len = strlen(buff);
      buff[len]   = '$';
      buff[len+1] = '\0';
    }
    return true;
 } 
 } // while looking for non-blank, non-preprocessor lines
}

char *TokenStream::get_upto(char ch, bool discard_ch)
// Grab characters from the stream, upto (and optionally including) ch.
// if anything goes wrong we throw a wobbly.
// *this routine (for now) just works for the prepro*
// *fix 1.2.1 (Peter) Strip out C++ line comments if we're grabbing the whole line
{
  bool found_end;
  start_P = P;
  while(*P && *P != ch) P++;
  found_end = *P == ch;
  if (! discard_ch) P++;
  end_P = P;
  if (discard_ch) P++;
  if (found_end) {
      char *str = get_str(tbuff);
      if (ch=='\0') { // special case of grabbing the whole line
      // *fix 1.2.2 (Eric) strip out any C++ comments properly
      // *fix 1.2.4 Discard any \r found at end of line (DOS files in Linux)
          for (char *p = str; *p; ++p) {
              if ((p[0] == '/' && p[1] == '/') || p[0] == '\r') {
                  *p = '\0';
                  break;
              }
	
          }
      }
      return str;
  }
  else return NULL;
}

void TokenStream::discard_line()
{
 *P = 0; skip_whitespace();
}

// *fix 0.9.3 This was ignoring blank lines & generally messing
//  up the template line number diagnostics.  But it's still
//  giving grief - need to handle the case where there's something
//  still in the input buffer (as is usually the case)
void TokenStream::grab_line(char *buff)
{  
  skip_whitespace();
  start_P = P;
  P += strlen(P);
  end_P = P;
  get_str(buff);
  
  //char lbuff[LINESIZE];
  //inf->getline(lbuff,LINESIZE); 
  //strcpy(buff,lbuff);
 
}

void TokenStream::insert_string(char *str)
// stuff characters into the stream!
// for now, it effectively discards what was _in_ the buffer;
// this is fine for its current application, which is to execute
// commands..
{
 set_str(buff);
 strcpy(P,str);
}

bool no_new_line = false;

bool TokenStream::skip_whitespace()
{
 top:
   while(*P && isspace(*P)) P++;
   if (*P == 0) {
     if(no_new_line || !fetch_line()) return false; // EOF will pass through as T_END
     goto top;
   } else
   if (*P == '/') { //...filter out comments at this level!!
       if (*(P+1)=='/') { *P = '\0'; goto top; } 
       else
       if (*(P+1)=='*') { 
           P++; in_comment = true;
           while (true){ 
               if (*P++=='*' && *P=='/') { P++; in_comment = false; goto top; }
               if (*P == 0) if(!fetch_line()) {
                   fatal_error(*this,"unexpected end of file in comment");
                   return false;
               }
           }
       }
   }
   return true;
}

int grab_alias_args(char *ptr, char **args)
{
 int nargs = 0;
 char *tok = strtok(ptr," "); //Utils::quote_strtok(ptr);
 while (tok != NULL) {
	 *args++ = tok;
	 ++nargs;
	 tok = strtok(NULL," "); //Utils::quote_strtok(NULL);
 }
 return nargs;
}

void separate_alias_commands(TokenStream& tok)
{
// approved way to fetch the whole line
 char *line = strdup(tok.get_upto(0,true));  
 char *cmds[10], buff[80];
 int k = 0;
 // break up into individual @-commands (need to do this separately)
 char *cmd = strtok(line,"@");
 while (cmd) { 
   cmds[k++] = cmd;
   cmd = strtok(NULL,"@");
 }

 // insert the commands back into the stream 
 // shifting the current position is necessary to prevent
 // runaway substition of 'cd' etc.
 for(int i = 0; i < k; i++) {
   sprintf(buff,"# %s",cmds[i]);
   tok.insert_string(buff);
   tok.current(tok.current()+1);
   // *fix 1.2.0 NB to switch off C string mode when calling do_prepro_directive()
   tok.c_string_mode(false);
   try {
     do_prepro_directive(tok);   
   } catch(string msg) { }
   tok.c_string_mode(true);
 }
}

void TokenStream::skip_digits()
{
 while(isdigit(*P)) P++;
}

static bool first_token_in(char *buff, char *P)
{
	if (P == buff) return true;
	P--;
	while (P != buff && isspace(*P)) P--;
	return P == buff && isspace(*P);
}

// *change 1.2.2 I've separated out the macro substitution code from next()
// and broken it into the two cases, C macros and aliases, explicitly.

bool TokenStream::macro_attempt_process(char*& p, char *out, char *tok)
{
   PMEntry pme = macro_lookup(tok);
   *out = '\0';
   if (! pme || pme->is_alias) return false;
   else {
       char *old_P = current();
       current(p);
       macro_process(pme,out);
       p = current();
       current(old_P);
   }
   return true;
}

void TokenStream::macro_process(PMEntry pme, char *out)
{
    char *args[MAX_MACRO_ARGS];
    char temp_buff[TT_BUFFSIZE];
    int nargs;
    char *subst;
    if (pme->nargs > 0) {
       if (!pme->subst) { // Builtin macro
            handle_builtin_macro(tbuff,pme->nargs);
            subst = tbuff;
       } else {
		  nargs = grab_actual_args(*this,args);  // regular C-style macro
          if (nargs != pme->nargs) fatal_error(*this,"wrong no. of arguments for this macro");
          substitute(*this,temp_buff, args, pme->subst);
          subst = temp_buff;
       }    
    } else 
       subst = pme->subst;

    if (! out) insert(P,subst);
          else strcpy(out,subst);
}

void TokenStream::alias_process(PMEntry pme)
{
    char *args[MAX_MACRO_ARGS];
    char temp_buff[TT_BUFFSIZE];
    int nargs;
    if (pme->nargs > 0) {		  
		  nargs = grab_alias_args(P,args);
          set_str(buff); 
          if (nargs != pme->nargs) fatal_error(*this,"wrong no. of arguments for this macro");
          substitute(*this,temp_buff, args, pme->subst);
          insert(P,temp_buff);
    } else 
       insert(P,pme->subst);

	 skip_whitespace();
	 if(*P=='@') {
         ++P;
  	     separate_alias_commands(*this);
		 discard_line();
     }  
}

int TokenStream::next()
{
try {  // *fix 1.01 fatal_error() will throw a string!
do_it_again:
  if (! skip_whitespace()) return 0;  // means: finis, end of file, bail out.
  if (iscsymf(*P)) { //--------------------- TOKENS --------------
     start_P = P;
     while (iscsym(*P)) P++;
     end_P = P;
     copy_str(tbuff,start_P,end_P);
     if (m_C_str) { // ie. suppress macro lookup in preprocessor directives
         PMEntry pme;
         // *add 1.2.4 Support for defined(MACRO) in #if directives
         // *fix 1.2.5 'defined MACRO' is also acceptable
         if (m_expecting_defined && strcmp(tbuff,"defined")==0) {
           m_C_str = false;
           int t = next();
           char mname[MAX_IDEN_SIZE];
           bool ok = (t == '(' || t == T_TOKEN);
           if (ok) {  
             if (t == '(') ok = (next() == T_TOKEN);     // skip the '('
             if (ok) {
               get_str(mname);                             // pick up the macro name
               if (t == '(') next();                       // skip the ')'
               insert(P,(char*)(macro_lookup(mname) ? "1" : "0"));  
               m_C_str = true;
               goto do_it_again;
             }
           } 
           m_C_str = true;
           if (! ok) fatal_error(*this,"defined takes one macro argument");
         } else {
          pme = macro_lookup(tbuff);
          if (pme) {
             if (pme->is_alias) {
                 if (! first_token_in(buff,start_P)) return T_TOKEN;
                 else alias_process(pme);
             } else
             macro_process(pme,NULL);
             goto do_it_again;
          }
          // *fix 1.2.7 in #if expressions, all non-macros evaluate as 0
          else if (m_expecting_defined) {
             insert(P,"0");
             goto do_it_again;
          }
         }
     }
     return T_TOKEN;
  } else
  if (isdigit(*P)  ||  *P == '.' && isdigit(*(P+1))) { //------- NUMBERS ------------------
    int ntype = int_type = T_INT;   // until proved otherwise!
     start_P = P;
     if (*P != '.') {
      if (*P == '0') {
        // actual verification of hex or octal constants must happen in lexer
        if (*(P+1) == 'x') {       // hex constant
          while (isalnum(*P)) P++; // a preliminary check!
          ntype = int_type = T_HEX;
        } else 
  	 if (isdigit(*(P+1))) {      // octal constant
         skip_digits();
         ntype = int_type = T_OCT;
	}
	else skip_digits();         // plain zero!
      } else {
        P++;                        // skip first - might be '-'
        skip_digits();
      }
     }
     if (*P == '.') {               // (opt) fractional part
        P++;
        skip_digits();
        ntype = T_DOUBLE;
     }
     if (*P == 'e' || *P == 'E') { // (opt) exponent part
        P++;
        if (*P == '+' || *P == '-') P++;  // (opt) exp sign
        skip_digits();
        ntype = T_DOUBLE;
     }
     if (*P == 'f' || *P == 'F')      { P++; ntype = T_FLOAT; }
     // *fix 1.2.6 long integer constants ending with 'L' are now acceptable 
     else if (*P == 'l' || *P == 'L') { P++; ntype = T_INT;  }
     end_P = P;
     return ntype;
  } else
  if (*P == '\"' || *P == '\'') { //------------CHAR OR STRING CONSTANT-------
     char ch, endch = *P++;  char *p = sbuff;
     start_P = sbuff;
next_string:
     while (*P && *P != endch) {
         if (*P == '\\' && m_C_str) {
             P++;
             switch(*P) {
             case '\\': ch = '\\'; break;
             case 'n':  ch = '\n'; break;
             case 'r':  ch = '\r'; break;
             case 't':  ch = '\t'; break;
             case 'b':  ch = '\b'; break;
             case '\"': ch = '\"'; break;
             case '\'': ch = '\''; break;
             case '0':  { //..collecting OCTAL constant
                char *start_oct = P;
                skip_digits();  
                copy_str(obuff,start_oct,P);
                ch = (char)convert_int(obuff,8);
                P--;  // leave us on last digit
		} break;
            // *fix 1.1.2 We were not letting non-escape sequences through...
			 default: *p++ = '\\'; ch = *P; break; 
             } // switch
             *p++ = ch; P++;
         } else *p++ = *P++;
     } 
     if (! *P) fatal_error(*this,"Unterminated string constant");
     P++;  // skip the endch
     *p = '\0';
     end_P = p;
// *add 1.1.1 adjacent quoted text
// *fix 1.1.4 gave preprocessor directives the heebies
	 if (endch=='\"') {
	 if (m_C_str) {
           skip_whitespace();
           if (*P == '\"') { 
               P++;                         // will be concatenated!
	       goto next_string;            // so go back & keep grabbing...
	   }
         }
       return  T_STRING; 
     }
     else return T_CHAR;
  } else
  return *P++;
 } catch(...) {
   return ' ';
 }
}

int TokenStream::look_ahead(bool skip_wspace)
//*OPT* Can inline this!
{
  if(skip_wspace) skip_whitespace(); 
  return *P;
}

int TokenStream::peek_ahead(int count)
{
 return *(P+count);
}

char *TokenStream::get_string()
{
	return sbuff;
}

char *TokenStream::peek_next_token()
{
// This is a hack and only use it if you are slowly going mad with frustration.
// It will return an empty buffer if there's no more tokens on the current line.
  char *ptr = P;
  while (*ptr && !iscsym(*ptr)) ptr++;
  char *start_p = ptr;
  if (ptr) {
    while (iscsym(*ptr)) ptr++;
  } 
  copy_str(tbuff,start_p,ptr);
  return tbuff;
}

char *TokenStream::get_str(char *tok)
{
 if (tok==NULL) tok = tbuff; 
 copy_str(tok,start_P,end_P);
 return tok;
}

char *TokenStream::get_token()
{  return tbuff; }

double TokenStream::get_float()
{
 char buff[20];
 return atof(get_str(buff));
}

int TokenStream::get_int()
{
 char buff[20];
 return convert_int(get_str(buff),int_type == T_INT ? 10 : 16);
} 

double TokenStream::next_float()
{
 int t;
 do {
  t = next();
  if (t == T_NUMBER || t == T_END) return get_float();
 } while (t != T_END);
 return 0.0;
}

void TokenStream::set_include_dir(const char *s)
{
// *fix 1.2.2 Check for too many include paths
    if (mNoIncludePaths+1 >= MAX_INCLUDE_PATHS) {
        cerr << "Out of room for include paths!" << endl;
        return;
    }
    string path = s;
    Utils::check_path_end(path);
    mIncludeDir[mNoIncludePaths] = path;
    ++mNoIncludePaths;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -