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

📄 chap9.lst

📁 The Art of C++一书的配套源代码
💻 LST
📖 第 1 页 / 共 3 页
字号:
  // Load the program to execute. 
  if(!load_program(p_buf, argv[1])) return 1; 
 
  // Set program pointer to start of program buffer. 
  prog = p_buf; 
 
  try { 
    // Find the location of all functions 
    // and global variables in the program. 
    prescan(); 
 
    // Next, set up the call to main(). 
 
    // Find program starting point. 
    prog = find_func("main"); 
 
    // Check for incorrect or missing main() function. 
    if(!prog) {  
      cout << "main() Not Found\n"; 
      return 1; 
    } 
 
    // Back up to opening (. 
    prog--; 
 
    // Set the first token to main 
    strcpy(token, "main"); 
 
    // Call main() to start interpreting. 
    call(); 
  }  
  catch(InterpExc exc) { 
    sntx_err(exc.get_err()); 
    return 1; 
  } 
  catch(bad_alloc exc) { 
    cout << "Out Of Memory\n"; 
    return 1; 
  } 
 
  return ret_value; 
} 
 
// Load a program. 
bool load_program(char *p, char *fname) 
{ 
  int i=0; 
 
  ifstream in(fname, ios::in | ios::binary); 
  if(!in) { 
    cout << "Cannot Open file.\n"; 
    return false; 
  } 
 
  do { 
    *p = in.get(); 
    p++; i++; 
  } while(!in.eof() && i < PROG_SIZE); 
 
  if(i == PROG_SIZE) { 
    cout << "Program Too Big\n"; 
    return false; 
  } 
 
  // Null terminate the program. Skip any EOF 
  // mark if present in the file. 
  if(*(p-2) == 0x1a) *(p-2) = '\0'; 
  else *(p-1) = '\0'; 
 
  in.close(); 
 
  return true; 
} 
 
// Find the location of all functions in the program 
// and store global variables.  
void prescan() 
{ 
  char *p, *tp; 
  char temp[MAX_ID_LEN+1]; 
  token_ireps datatype;  
  func_type ft; 
 
  // When brace is 0, the current source position 
  // is outside of any function.  
  int brace = 0;  
 
  p = prog; 
 
  do { 
    // Bypass code inside functions 
    while(brace) { 
      get_token(); 
      if(tok == END) throw InterpExc(UNBAL_BRACES); 
      if(*token == '{') brace++; 
      if(*token == '}') brace--; 
    } 
 
    tp = prog; // save current position 
    get_token(); 
 
    // See if global var type or function return type. 
    if(tok==CHAR || tok==INT) {  
      datatype = tok; // save data type 
      get_token(); 
 
      if(token_type == IDENTIFIER) { 
        strcpy(temp, token); 
        get_token(); 
 
        if(*token != '(') { // must be global var 
          prog = tp; // return to start of declaration 
          decl_global(); 
        } 
        else if(*token == '(') { // must be a function 
 
          // See if function already defined. 
          for(unsigned i=0; i < func_table.size(); i++) 
            if(!strcmp(func_table[i].func_name, temp)) 
              throw InterpExc(DUP_FUNC); 
 
          ft.loc = prog; 
          ft.ret_type = datatype; 
          strcpy(ft.func_name, temp); 
          func_table.push_back(ft); 
 
          do { 
            get_token(); 
          } while(*token != ')'); 
          // Next token will now be opening curly  
          // brace of function. 
        } 
        else putback(); 
      } 
    } 
    else { 
      if(*token == '{') brace++; 
      if(*token == '}') brace--; 
    } 
  } while(tok != END); 
  if(brace) throw InterpExc(UNBAL_BRACES); 
  prog = p; 
} 
 
// Interpret a single statement or block of code. When 
// interp() returns from its initial call, the final 
// brace (or a return) in main() has been encountered. 
void interp() 
{ 
  int value; 
  int block = 0; 
 
  do { 
    // Don't interpret until break is handled. 
    if(breakfound) return; 
 
    token_type = get_token(); 
 
    // See what kind of token is up. 
    if(token_type == IDENTIFIER || 
       *token == INC || *token == DEC) 
    { 
      // Not a keyword, so process expression.  
      putback();  // restore token to input stream for 
                  // further processing by eval_exp() 
      eval_exp(value); // process the expression 
      if(*token != ';') throw InterpExc(SEMI_EXPECTED); 
    } 
    else if(token_type==BLOCK) { // block delimiter? 
      if(*token == '{') { // is a block 
        block = 1; // interpreting block, not statement 
        // Record nested scope. 
        nest_scope_stack.push(local_var_stack.size()); 
      } 
      else { // is a }, so reset scope and return 
        // Reset nested scope. 
        local_var_stack.resize(nest_scope_stack.top()); 
        nest_scope_stack.pop(); 
        return; 
      } 
    } 
    else // is keyword 
      switch(tok) { 
        case CHAR: 
        case INT:     // declare local variables 
          putback(); 
          decl_local(); 
          break; 
        case RETURN:  // return from function call 
          func_ret(); 
          return; 
        case IF:      // process an if statement 
          exec_if(); 
          break; 
        case ELSE:    // process an else statement 
          find_eob(); // find end of else block 
                      // and continue execution 
          break; 
        case WHILE:   // process a while loop 
          exec_while(); 
          break; 
        case DO:      // process a do-while loop 
          exec_do(); 
          break; 
        case FOR:     // process a for loop 
          exec_for(); 
          break; 
        case BREAK:   // handle break 
          breakfound = true; 
 
          // Reset nested scope. 
          local_var_stack.resize(nest_scope_stack.top()); 
          nest_scope_stack.pop(); 
          return; 
        case SWITCH:  // handle a switch statement 
          exec_switch(); 
          break; 
        case COUT:    // handle console output 
          exec_cout(); 
          break; 
        case CIN:     // handle console input 
          exec_cin(); 
          break; 
        case END: 
          exit(0); 
      } 
  } while (tok != END && block); 
  return; 
} 
 
// Return the entry point of the specified function. 
// Return NULL if not found. 
char *find_func(char *name) 
{ 
  unsigned i; 
 
  for(i=0; i < func_table.size(); i++) 
    if(!strcmp(name, func_table[i].func_name)) 
      return func_table[i].loc; 
 
  return NULL; 
} 
 
// Declare a global variable. 
void decl_global() 
{ 
  token_ireps vartype; 
  var_type vt; 
 
  get_token(); // get type 
 
  vartype = tok; // save var type 
 
  // Process comma-separated list. 
  do { 
    vt.v_type = vartype; 
    vt.value = 0; // init to 0 
    get_token(); // get name 
 
    // See if variable is a duplicate. 
    for(unsigned i=0; i < global_vars.size(); i++) 
      if(!strcmp(global_vars[i].var_name, token)) 
        throw InterpExc(DUP_VAR); 
 
    strcpy(vt.var_name, token); 
    global_vars.push_back(vt); 
 
    get_token(); 
  } while(*token == ','); 
 
  if(*token != ';') throw InterpExc(SEMI_EXPECTED); 
} 
 
// Declare a local variable. 
void decl_local() 
{ 
  var_type vt; 
 
  get_token(); // get var type 
  vt.v_type = tok; // store type 
 
  vt.value = 0; // init var to 0 
 
  // Process comma-separated list. 
  do { 
    get_token(); // get var name 
 
    // See if variable is already the name 
    // of a local variable in this scope. 
    if(!local_var_stack.empty()) 
    for(int i=local_var_stack.size()-1; 
        i >= nest_scope_stack.top(); i--) 
    { 
      if(!strcmp(local_var_stack[i].var_name, token)) 
        throw InterpExc(DUP_VAR); 
    } 
 
    strcpy(vt.var_name, token); 
    local_var_stack.push_back(vt); 
    get_token(); 
  } while(*token == ','); 
 
  if(*token != ';') throw InterpExc(SEMI_EXPECTED); 
} 
 
// Call a function. 
void call() 
{ 
  char *loc, *temp; 
  int lvartemp; 
 
  // First, find entry point of function. 
  loc = find_func(token); 
 
  if(loc == NULL) 
    throw InterpExc(FUNC_UNDEF); // function not defined 
  else { 
    // Save local var stack index. 
    lvartemp = local_var_stack.size(); 
 
    get_args(); // get function arguments 
    temp = prog; // save return location 
 
    func_call_stack.push(lvartemp); // push local var index 
 
    prog = loc; // reset prog to start of function 
    get_params(); // load the function's parameters with 
                  // the values of the arguments 
 
    interp(); // interpret the function 
 
    prog = temp; // reset the program pointer 
 
    if(func_call_stack.empty()) throw InterpExc(RET_NOCALL); 
 
    // Reset local_var_stack to its previous state. 
    local_var_stack.resize(func_call_stack.top());  
    func_call_stack.pop(); 
  } 
} 
 
// Push the arguments to a function onto the local 
// variable stack. 
void get_args() 
{ 
  int value, count, temp[NUM_PARAMS]; 
  var_type vt; 
 
  count = 0; 
  get_token(); 
  if(*token != '(') throw InterpExc(PAREN_EXPECTED); 
 
  // Process a comma-separated list of values. 
  do { 
    eval_exp(value); 
    temp[count] = value; // save temporarily 
    get_token(); 
    count++; 
  } while(*token == ','); 
  count--; 
 
  // Now, push on local_var_stack in reverse order. 
  for(; count>=0; count--) { 
    vt.value = temp[count]; 
    vt.v_type = ARG; 
    local_var_stack.push_back(vt); 
  } 
} 
 
// Get function parameters. 
void get_params() 
{ 
  var_type *p; 
  int i; 
 
  i = local_var_stack.size()-1; 
 
  // Process comma-separated list of parameters. 
  do {  
    get_token(); 
    p = &local_var_stack[i]; 
    if(*token != ')' ) { 
      if(tok != INT && tok != CHAR) 
        throw InterpExc(TYPE_EXPECTED); 
 
      p->v_type = tok; 
      get_token(); 
 
      // Link parameter name with argument already on 
      // local var stack. 
      strcpy(p->var_name, token); 
      get_token(); 
      i--; 
    } 
    else break; 
  } while(*token == ','); 
 
  if(*token != ')') throw InterpExc(PAREN_EXPECTED); 
} 
 
// Return from a function. 
void func_ret() 
{ 
  int value; 
 
  value = 0; 
 
  // Get return value, if any. 
  eval_exp(value); 
 
  ret_value = value; 
} 
 
// Assign a value to a variable. 
void assign_var(char *vname, int value) 
{ 
  // First, see if it's a local variable. 
  if(!local_var_stack.empty()) 
    for(int i=local_var_stack.size()-1; 
        i >= func_call_stack.top(); i--) 
    { 
      if(!strcmp(local_var_stack[i].var_name, 
                 vname)) 
      { 
        if(local_var_stack[i].v_type == CHAR) 
          local_var_stack[i].value = (char) value; 
        else if(local_var_stack[i].v_type == INT) 
          local_var_stack[i].value = value; 
        return; 
      } 
    } 
 
  // Otherwise, try global vars. 
  for(unsigned i=0; i < global_vars.size(); i++) 
    if(!strcmp(global_vars[i].var_name, vname)) { 
      if(global_vars[i].v_type == CHAR) 
        global_vars[i].value = (char) value; 
      else if(global_vars[i].v_type == INT) 
        global_vars[i].value = value; 
      return; 
    } 
 
  throw InterpExc(NOT_VAR); // variable not found 
} 
 
// Find the value of a variable. 
int find_var(char *vname) 
{ 
  // First, see if it's a local variable. 
  if(!local_var_stack.empty()) 
    for(int i=local_var_stack.size()-1; 
        i >= func_call_stack.top(); i--) 
    { 
      if(!strcmp(local_var_stack[i].var_name, vname)) 
        return local_var_stack[i].value; 
    } 
 
  // Otherwise, try global vars. 
  for(unsigned i=0; i < global_vars.size(); i++) 
    if(!strcmp(global_vars[i].var_name, vname)) 
      return global_vars[i].value; 
 
  throw InterpExc(NOT_VAR); // variable not found 
} 
 
// Execute an if statement. 
void exec_if() 
{ 
  int cond; 
 
  eval_exp(cond); // get if expression. 
 
  if(cond) { // if true, process target of IF 
    // Confirm start of block. 
    if(*token != '{')  
      throw InterpExc(BRACE_EXPECTED); 
 
    interp(); 
  } 
  else { 
    // Otherwise skip around IF block and 
    // process the ELSE, if present. 
 
    find_eob(); // find start of next line 
    get_token(); 
 
    if(tok != ELSE) { 
      // Restore token if no ELSE is present. 
      putback();   
      return; 
    } 
 
    // Confirm start of block. 
    get_token(); 
    if(*token != '{')  
      throw InterpExc(BRACE_EXPECTED); 
    putback(); 
 
    interp(); 
  } 
} 
 
// Execute a switch statement. 
void exec_switch() 
{ 
  int sval, cval; 
  int brace; 
 
  eval_exp(sval); // Get switch expression. 
 
  // Check for start of block. 
  if(*token != '{')  
    throw InterpExc(BRACE_EXPECTED); 
 
  // Record new scope. 
  nest_scope_stack.push(local_var_stack.size()); 
 
  // Now, check case statements. 
  for(;;) { 
    brace = 1; 
    // Find a case statement. 
    do { 
      get_token(); 
      if(*token == '{') brace++; 
      else if(*token == '}') brace--;  
    } while(tok != CASE && tok != END && brace); 
 
    // If no matching case found, then skip. 
    if(!brace) break; 
 
    if(tok == END) throw InterpExc(SYNTAX); 
 
    // Get value of the case statement. 
    eval_exp(cval); 
 
    // Read and discard the : 
    get_token(); 
 
    if(*token != ':') 
      throw InterpExc(COLON_EXPECTED); 
 
    // If values match, then interpret. 
    if(cval == sval) { 
      brace = 1; 
      do { 
        interp(); 
 
        if(*token == '{') brace++; 
        else if(*token == '}') brace--; 
      } while(!breakfound && tok != END && brace); 
 
      // Find end of switch statement. 
      while(brace) { 
        get_token(); 
        if(*token == '{') brace++; 
        else if(*token == '}') brace--; 
      } 
      breakfound = false; 
 
      break; 
    } 
  }  
} 
 
// Execute a while loop. 
void exec_while() 
{ 
  int cond; 
  char *temp; 
 
  putback(); // put back the while 
  temp = prog; // save location of top of while loop 
 
  get_token(); 
  eval_exp(cond); // check the conditional expression 
 
  // Confirm start of block. 
  if(*token != '{')  
    throw InterpExc(BRACE_EXPECTED); 
 
  if(cond) 
    interp(); // if true, interpret 
  else { // otherwise, skip to end of loop 
    find_eob(); 
    return; 
  } 
 
  prog = temp; // loop back to top 
 
  // Check for break in loop. 
  if(breakfound) { 
    // Find start of loop block. 
    do { 
      get_token(); 
    } while(*token != '{' && tok != END); 
 
    putback(); 
    breakfound = false; 
    find_eob(); // now, find end of loop 
    return; 
  } 
} 
 
// Execute a do loop. 
void exec_do() 
{ 
  int cond; 
  char *temp; 
 
 
  // Save location of top of do loop. 
  putback(); // put back do 
  temp = prog; 
 
  get_token(); // get start of loop block 
 
  // Confirm start of block. 
  get_token(); 
  if(*token != '{')  
    throw InterpExc(BRACE_EXPECTED); 
  putback(); 
 
  interp(); // interpret loop 
 
  // Check for break in loop. 
  if(breakfound) { 
    prog = temp; 
    // Find start of loop block. 
    do { 
      get_token(); 
    } while(*token != '{' && tok != END); 
 
    // Find end of while block.     
    putback(); 
    find_eob(); 
 
    // Now, find end of while expression. 
    do { 
      get_token(); 
    } while(*token != ';' && tok != END); 
    if(tok == END) throw InterpExc(SYNTAX); 
 
    breakfound = false; 
    return; 
  } 
 
  get_token(); 
  if(tok != WHILE) throw InterpExc(WHILE_EXPECTED); 
 
  eval_exp(cond); // check the loop condition 
 
  // If true loop; otherwise, continue on. 
  if(cond) prog = temp; 
} 
 
// Execute a for loop. 
void exec_for() 
{ 
  int cond; 
  char *temp, *temp2; 
  int paren ; 
 

⌨️ 快捷键说明

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