簡單的C++解釋器1.02


承接上一篇日志我對原來的解釋器做一點小小的改動.

大致增加了如下特性:

1, 允許for(int i = 0; i < 23; i++) 這樣使用for循環, 即在for的括號內部定義循環控制變量.

2,增加了continue關鍵字.

3, 增加了對一些新的數據類型的支持, bool, char, short, int, long, float, double都給予了支持.

4, 增加了true/false關鍵字, 直接對bool變量賦值.

關於增加新的數據類型這件事, 一開始我的想法是:

定義一個結構體, 用來表達上面支持的所有類型, 該結構體會根據實際的類型返回正確的值.

 1 struct var
 2 {
 3     int type;
 4     union
 5     {
 6         char char_val;
 7         bool bool_val;
 8         int int_val;
 9         double double_val;
10         float float_val;
11         long long_val;
12     }value;
13 };

當做加法運算的時候, c = a + b; 這里a 和b可以利用某種運算直接返回正確的值, 這樣就可以依賴C++語言自身來處理這個加法了.

不過至於如何能讓一個結構體根據實際類型返回正確的值這個問題, 其實就是在構造一種動態類型, 仔細想想python里面的動態類型應該就是用C這樣寫出來的.

關於如何實現動態語言類型, 可以看看<python源碼剖析>的吧, 不過這里就不搞這件事了, 我直接用一些判斷擼過了~

 1 //這是個匿名的var結構體, 存儲了變量的類型和值, 但是是個匿名的,
 2 //類似python里面的變量的引用的概念
 3 struct anonymous_var
 4 {
 5     token_ireps var_type; // data type
 6     long int_value;
 7     double float_value;
 8 };
 9 // This structure encapsulates the info
10 // associated with variables.
11 struct var
12 {
13     char var_name[MAX_ID_LEN + 1]; // name
14     anonymous_var value;
15 };

上面就是我現在使用的結構體的代碼, 用long值存儲所有的整型數據, double值存儲所有的浮點數.

做各種運算的時候, 會將低級別的統一成高級別的來操作, 就是做了一下算數轉換, 這樣實現起來比較簡單.

所有的整型之間運算使用long值來結算, 所有浮點使用double值類結算, 整型和浮點之間運算會把整型數據先轉化成浮點的.

結構體里面只存了long和double, 而在需要使用相應的值的時候(比如要打印一個char)會再把對應的高級類型轉化回去, 可以參看exec_cout函數體.

下面是我改進后的代碼:

敬告, 代碼依然很脆弱, 請使用簡單而且語法正確的程序測試, 而且可能我的改動會引入更多的bug, 所以僅供參考.

View Code
   1 /************************************************************************/
   2 /* mccommon.h, 頭文件里面聲明了Minicpp使用的函數, 聲明主要使用的
   3  * 最新修改時間2012-9-15, 主要增加了var.cpp里面函數的聲明                */
   4 /************************************************************************/
   5 
   6 const int MAX_T_LEN  = 128;   // max token length
   7 const int MAX_ID_LEN = 31;    // max identifier length
   8 const int PROG_SIZE  = 10000; // max program size
   9 const int NUM_PARAMS = 31;    // max number of parameters
  10 
  11 // Enumeration of token types.
  12 enum tok_types { UNDEFTT, DELIMITER, IDENTIFIER,
  13                  NUMBER, KEYWORD, TEMP, STRING, BLOCK, TYPE
  14                };
  15 
  16 // Enumeration of internal representation of tokens.
  17 //大部分指定的是C++里面的關鍵字, 當然cout和cin也被加進來了
  18 enum token_ireps { UNDEFTOK, ARG, BOOL, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, FALSE, TRUE, SWITCH,
  19                    CASE, IF, ELSE, FOR, DO, WHILE, BREAK,
  20                    RETURN, COUT, CIN, END, ENDL, DEFAULT, CONTINUE, NONE
  21                  };
  22 
  23 
  24 //上面兩個枚舉的區別是上面的比較廣義,指代各種token的類型, 比如block, 這個是不會是關鍵字的,
  25 //下面的可以理解成就是關鍵字
  26 
  27 //這是個匿名的var結構體, 存儲了變量的類型和值, 但是是個匿名的,
  28 //類似python里面的變量的引用的概念
  29 struct anonymous_var
  30 {
  31     token_ireps var_type; // data type
  32     long int_value;
  33     double float_value;
  34 };
  35 // This structure encapsulates the info
  36 // associated with variables.
  37 struct var
  38 {
  39     char var_name[MAX_ID_LEN + 1]; // name
  40     anonymous_var value;
  41 };
  42 
  43 
  44 // This structure encapsulates function info.
  45 struct func_type
  46 {
  47     char func_name[MAX_ID_LEN + 1]; // name
  48     token_ireps ret_type; // return type
  49     char *loc; // location of entry point in program
  50 };
  51 
  52 // Enumeration of two-character operators, such as <=.
  53 //這里注意從1開始, 以免用到0出現誤解.
  54 enum double_ops { LT = 1, LE, GT, GE, EQ, NE, LS, RS, INC, DEC };
  55 
  56 // These are the constants used when throwing a
  57 // syntax error exception.
  58 //
  59 // NOTE: SYNTAX is a generic error message used when
  60 // nothing else seems appropriate.
  61 enum error_msg
  62 {
  63     SYNTAX, NO_EXP, NOT_VAR, DUP_VAR, DUP_FUNC,
  64     SEMI_EXPECTED, UNBAL_BRACES, FUNC_UNDEF,
  65     TYPE_EXPECTED, RET_NOCALL, PAREN_EXPECTED,
  66     WHILE_EXPECTED, QUOTE_EXPECTED, DIV_BY_ZERO,
  67     BRACE_EXPECTED, COLON_EXPECTED, UNSUPPORTED_TYPE
  68     //最后加了一個UNSUPPORTED_TYPE, 是因為最近只支持一些簡單的內建類型
  69 };
  70 
  71 
  72 
  73 
  74 
  75 //下面這些是全局變量, 用來控制解析的, 估計以后如果重構的話就是parser類的主要成員變量.
  76 extern char *prog;  // current location in source code
  77 extern char *p_buf; // points to start of program buffer
  78 
  79 extern char token[MAX_T_LEN + 1]; // string version of token
  80 extern tok_types token_type; // contains type of token
  81 extern token_ireps tok; // internal representation of token
  82 
  83 extern anonymous_var ret_value; // function return value
  84 
  85 extern bool breakfound; // true if break encountered
  86 extern bool continuefound;//true if continue encountered
  87 
  88 // Exception class for Mini C++.
  89 class InterpExc
  90 {
  91     error_msg err;
  92 public:
  93     InterpExc(error_msg e)
  94     {
  95         err = e;
  96     }
  97     error_msg get_err()
  98     {
  99         return err;
 100     }
 101 };
 102 
 103 // Interpreter prototypes.
 104 void prescan();
 105 void decl_global();
 106 void call();
 107 void putback();
 108 void decl_local();
 109 void exec_if();
 110 void find_eob();
 111 void exec_for();
 112 void exec_switch();
 113 void get_params();
 114 void get_args();
 115 void exec_while();
 116 void exec_do();
 117 void exec_cout();
 118 void exec_cin();
 119 void assign_var(char *var_name, anonymous_var value);
 120 bool load_program(char *p, char *fname);
 121 anonymous_var find_var(char *s);
 122 void interp();
 123 void func_ret();
 124 char *find_func(char *name);
 125 bool is_var(char *s);
 126 token_ireps find_var_type(char *s);
 127 void find_eol();
 128 
 129 
 130 // Parser prototypes, 這些函數主要用來parse表達式.
 131 void eval_exp(anonymous_var &value);
 132 void eval_exp0(anonymous_var &value);
 133 void eval_exp1(anonymous_var &value);
 134 void eval_exp2(anonymous_var &value);
 135 void eval_exp3(anonymous_var &value);
 136 void eval_exp4(anonymous_var &value);
 137 void eval_exp5(anonymous_var &value);
 138 void atom(anonymous_var &value);
 139 void sntx_err(error_msg error);
 140 void putback();
 141 bool isdelim(char c);
 142 token_ireps look_up(char *s);
 143 anonymous_var find_var(char *s);
 144 tok_types get_token();
 145 int internal_func(char *s);
 146 bool is_var(char *s);
 147 
 148 // "Standard library" prototypes, 這幾個函數里面是調用了一下C++的庫函數, 封裝了一下.
 149 anonymous_var call_getchar();
 150 anonymous_var call_putchar();
 151 anonymous_var call_abs();
 152 anonymous_var call_rand();
 153 
 154 
 155 
 156 //下面這些是為了支持多種類型二增加的一些函數.
 157 //在var.cpp里面實現.
 158 anonymous_var add(anonymous_var &a, anonymous_var &b);
 159 anonymous_var sub(anonymous_var &a, anonymous_var &b);
 160 anonymous_var mul(anonymous_var &a, anonymous_var &b);
 161 anonymous_var div(anonymous_var &a, anonymous_var &b);
 162 void cin_var(anonymous_var &v);
 163 void cout_var(anonymous_var &v);
 164 bool is_valid_type(token_ireps ti);
 165 void init_var(anonymous_var &v);
 166 void neg_var(anonymous_var &v);
 167 bool zero(double x);
 168 void abs_var(anonymous_var &v);
 169 int cmp(anonymous_var &a, anonymous_var &b);
 170 bool is_float_type(token_ireps type);
 171 bool is_int_type(token_ireps type);
 172 bool get_bool_val(anonymous_var &v);
 173 void adaptive_assign_var(anonymous_var &a, anonymous_var &b);
 174 
 175 
 176 /********************************************************************
 177 var.cpp, 主要是為了增加對多種數值類型的支持而添加的
 178 目前支持bool, char, short, int, long, float, double
 179 基本只使用long和double進行結算.
 180 **********************************************************************/
 181 
 182 #include <iostream>
 183 #include <cmath>
 184 #include "mccommon.h"
 185 using namespace std;
 186 
 187 inline bool zero(double x)
 188 {
 189     const double EPS = 1e-9;
 190     return abs(x) < EPS;
 191 }
 192 bool is_int_type(token_ireps type)
 193 {
 194     if(type >= BOOL && type <= LONG) return true;
 195     return false;
 196 }
 197 bool is_float_type(token_ireps type)
 198 {
 199     if(type >= FLOAT && type <= DOUBLE) return true;
 200     else return false;
 201 }
 202 bool check_valid_type(anonymous_var &val)
 203 {
 204     if(!(is_int_type(val.var_type) || is_float_type(val.var_type))) return false;
 205     return true;
 206 }
 207 anonymous_var add(anonymous_var &a, anonymous_var &b)
 208 {
 209     if(!check_valid_type(a) || !check_valid_type(b)) throw InterpExc(UNSUPPORTED_TYPE);
 210     anonymous_var res;
 211     if(a.var_type > b.var_type) res.var_type = a.var_type;
 212     else res.var_type = b.var_type;
 213 
 214     if(is_int_type(res.var_type))
 215     {
 216         res.int_value = a.int_value + b.int_value;
 217     }
 218     else
 219     {
 220         if(is_int_type(a.var_type))
 221         {
 222             res.float_value = double(a.int_value) + b.float_value;
 223         }
 224         else if(is_int_type(b.var_type))
 225         {
 226             res.float_value = a.float_value + double(b.int_value);
 227         }
 228         else
 229         {
 230             res.float_value = a.float_value + b.float_value;
 231         }
 232     }
 233     return res;
 234 }
 235 
 236 anonymous_var sub(anonymous_var &a, anonymous_var &b)
 237 {
 238     if(!check_valid_type(a) || !check_valid_type(b)) throw InterpExc(UNSUPPORTED_TYPE);
 239     anonymous_var res;
 240     if(a.var_type > b.var_type) res.var_type = a.var_type;
 241     else res.var_type = b.var_type;
 242 
 243     if(is_int_type(res.var_type))
 244     {
 245         res.int_value = a.int_value - b.int_value;
 246     }
 247     else
 248     {
 249         if(is_int_type(a.var_type))
 250         {
 251             res.float_value = double(a.int_value) - b.float_value;
 252         }
 253         else if(is_int_type(b.var_type))
 254         {
 255             res.float_value = a.float_value - double(b.int_value);
 256         }
 257         else
 258         {
 259             res.float_value = a.float_value - b.float_value;
 260         }
 261     }
 262     return res;
 263 
 264 }
 265 
 266 anonymous_var mul(anonymous_var &a, anonymous_var &b)
 267 {
 268     if(!check_valid_type(a) || !check_valid_type(b)) throw InterpExc(UNSUPPORTED_TYPE);
 269     anonymous_var res;
 270 
 271     if(a.var_type > b.var_type) res.var_type = a.var_type;
 272     else res.var_type = b.var_type;
 273 
 274     if(is_int_type(res.var_type))
 275     {
 276         res.int_value = a.int_value * b.int_value;
 277     }
 278     else
 279     {
 280         if(is_int_type(a.var_type))
 281         {
 282             res.float_value = double(a.int_value) * b.float_value;
 283         }
 284         else if(is_int_type(b.var_type))
 285         {
 286             res.float_value = a.float_value * double(b.int_value);
 287         }
 288         else
 289         {
 290             res.float_value = a.float_value * b.float_value;
 291         }
 292     }
 293     return res;
 294 }
 295 
 296 anonymous_var div(anonymous_var &a, anonymous_var &b)
 297 {
 298     if(!check_valid_type(a) || !check_valid_type(b)) throw InterpExc(UNSUPPORTED_TYPE);
 299     anonymous_var res;
 300     if(a.var_type > b.var_type) res.var_type = a.var_type;
 301     else res.var_type = b.var_type;
 302 
 303     if(is_int_type(b.var_type))
 304     {
 305         if(0 == a.int_value) throw InterpExc(DIV_BY_ZERO);
 306     }
 307     else
 308     {
 309         if(zero(b.float_value)) throw InterpExc(DIV_BY_ZERO);
 310     }
 311 
 312     if(is_int_type(res.var_type))
 313     {
 314         res.int_value = a.int_value / b.int_value;
 315     }
 316     else
 317     {
 318         if(is_int_type(a.var_type))
 319         {
 320             res.float_value = double(a.int_value) / b.float_value;
 321         }
 322         else if(is_int_type(b.var_type))
 323         {
 324             res.float_value = a.float_value / double(b.int_value);
 325         }
 326         else
 327         {
 328             res.float_value = a.float_value / b.float_value;
 329         }
 330     }
 331     return res;
 332 }
 333 
 334 
 335 //因為現在我只用long 和double來存儲表示所有的數值類型,
 336 //在從控制台讀取內容的時候會不方便, 現在先用
 337 void cin_var(anonymous_var &v)
 338 {
 339     switch (v.var_type)
 340     {
 341     case BOOL:
 342     {
 343         bool tmp_var;
 344         cin >> tmp_var;
 345         v.int_value = tmp_var;
 346         break;
 347     }
 348     case CHAR:
 349     {
 350         char tmp_var;
 351         cin >> tmp_var;
 352         v.int_value = tmp_var;
 353         break;
 354     }
 355     case SHORT:
 356     {
 357         short tmp_var;
 358         cin >> tmp_var;
 359         v.int_value = tmp_var;
 360         break;
 361     }
 362     case INT:
 363     {
 364         int tmp_var;
 365         cin >> tmp_var;
 366         v.int_value = tmp_var;
 367         break;
 368     }
 369     case LONG:
 370     {
 371         long tmp_var;
 372         cin >> tmp_var;
 373         v.int_value = tmp_var;
 374         break;
 375     }
 376     case FLOAT:
 377     {
 378         float tmp_var;
 379         cin >> tmp_var;
 380         v.float_value = tmp_var;
 381         break;
 382     }
 383     case DOUBLE:
 384     {
 385         double tmp_var;
 386         cin >> tmp_var;
 387         v.float_value = tmp_var;
 388         break;
 389     }
 390     default:
 391         throw InterpExc(UNSUPPORTED_TYPE);
 392         break;
 393     }
 394 }
 395 
 396 
 397 //輸出的時候, 要先轉化成相應的類型, 然后再打印
 398 void cout_var(anonymous_var &v)
 399 {
 400     switch(v.var_type)
 401     {
 402     case BOOL:
 403         cout << bool(v.int_value != 0);
 404         break;
 405     case CHAR:
 406         cout << char(v.int_value);
 407         break;
 408     case SHORT:
 409         cout << short(v.int_value);
 410         break;
 411     case INT:
 412         cout << int(v.int_value);
 413         break;
 414     case LONG:
 415         cout << long(v.int_value);
 416         break;
 417     case FLOAT:
 418         cout << float(v.float_value);
 419         break;
 420     case DOUBLE:
 421         cout << double(v.float_value);
 422         break;
 423     default:
 424         throw InterpExc(UNSUPPORTED_TYPE);
 425         break;
 426     }
 427 }
 428 
 429 bool is_valid_type(token_ireps ti)
 430 {
 431     return ti >= BOOL && ti <= DOUBLE;
 432 }
 433 
 434 void init_var(anonymous_var &v)
 435 {
 436     v.int_value = 0;
 437     v.float_value = 0.0;
 438 }
 439 
 440 void neg_var(anonymous_var &v)
 441 {
 442     if(is_int_type(v.var_type))
 443     {
 444         v.int_value = -v.int_value;
 445     }
 446     else if(is_float_type(v.var_type))
 447     {
 448         v.float_value = v.float_value;
 449     }
 450     else
 451     {
 452         throw InterpExc(UNSUPPORTED_TYPE);
 453     }
 454 }
 455 
 456 void abs_var(anonymous_var &v)
 457 {
 458     if(is_int_type(v.var_type))
 459     {
 460         v.int_value = abs(v.int_value);
 461     }
 462     else if(is_float_type(v.var_type))
 463     {
 464         v.float_value = abs(v.float_value);
 465     }
 466     else
 467     {
 468         throw InterpExc(UNSUPPORTED_TYPE);
 469     }
 470 }
 471 
 472 
 473 
 474 int cmp(anonymous_var &a, anonymous_var &b)
 475 {
 476     if(!check_valid_type(a) || !check_valid_type(b)) throw InterpExc(UNSUPPORTED_TYPE);
 477     if(is_int_type(a.var_type))
 478     {
 479         if(is_int_type(b.var_type))
 480         {
 481             if(a.int_value == b.int_value) return 0;
 482             if(a.int_value < b.int_value) return -1;
 483             return 1;
 484         }
 485         else if(is_float_type(a.var_type))
 486         {
 487             if(zero(a.int_value - b.float_value)) return 0;
 488             if(a.int_value < b.float_value) return -1;
 489             return 1;
 490         }
 491     }
 492     else
 493     {
 494         if(is_int_type(b.var_type))
 495         {
 496             if(zero(a.float_value - b.int_value)) return 0;
 497             if(a.float_value < b.int_value) return -1;
 498             return 1;
 499         }
 500         else
 501         {
 502             if(zero(a.float_value - b.float_value)) return 0;
 503             if(a.float_value < b.float_value) return -1;
 504             return 1;
 505         }
 506     }
 507 }
 508 
 509 bool get_bool_val(anonymous_var &v)
 510 {
 511     bool bool_val = false;
 512     if(is_int_type(v.var_type))
 513     {
 514         bool_val = v.int_value != 0;
 515     }
 516     else if(is_float_type(v.var_type))
 517     {
 518         bool_val = !zero(v.float_value);
 519     }
 520     else
 521     {
 522         throw InterpExc(UNSUPPORTED_TYPE);
 523     }
 524     return bool_val;
 525 }
 526 
 527 
 528 //這個函數適配性地進行了賦值.
 529 void adaptive_assign_var(anonymous_var &a, anonymous_var &b)
 530 {
 531     if(!check_valid_type(a) || !check_valid_type(b)) throw InterpExc(UNSUPPORTED_TYPE);
 532 
 533     if(is_int_type(a.var_type))
 534     {
 535         if(is_int_type(b.var_type))
 536         {
 537             a.int_value = b.int_value;
 538         }
 539         else
 540         {
 541             a.int_value = int(b.float_value);
 542         }
 543     }
 544     else
 545     {
 546         if(is_int_type(b.var_type))
 547         {
 548             a.float_value = double(b.int_value);
 549         }
 550         else
 551         {
 552             a.float_value = b.float_value;
 553         }
 554     }
 555 }
 556 
 557 
 558 
 559 /*********************************************************************
 560  parser.cpp 用來遞歸下降地解析表達式, 使用anonymous_var類型傳遞中間結果
 561 *********************************************************************/
 562 
 563 
 564 // Recursive descent parser for integer expressions.
 565 //
 566 #include <iostream>
 567 #include <cstring>
 568 #include <cstdlib>
 569 #include <cctype>
 570 #include "mccommon.h"
 571 
 572 using namespace std;
 573 
 574 // This structure links a library function name
 575 // with a pointer to that function.
 576 struct intern_func_type
 577 {
 578     char *f_name; // function name
 579     anonymous_var (*p)();   // pointer to the function
 580 } intern_func[] =
 581 {
 582     "getchar", call_getchar,
 583     "putchar", call_putchar,
 584     "abs", call_abs,
 585     "rand", call_rand,
 586     "", 0  // null terminate the list
 587 };
 588 
 589 // Keyword lookup table.
 590 // Keywords must be entered lowercase.
 591 // 定義關鍵字, 對應一個tok的id, 能提高些效率
 592 struct commands
 593 {
 594     char command[20];
 595     token_ireps tok;
 596 } com_table[] =
 597 {
 598     "if", IF,
 599     "else", ELSE,
 600     "for", FOR,
 601     "do", DO,
 602     "while", WHILE,
 603     "bool", BOOL,
 604     "char", CHAR,
 605     "short", SHORT,
 606     "int", INT,
 607     "long", LONG,
 608     "float", FLOAT,
 609     "double", DOUBLE,
 610     "return", RETURN,
 611     "switch", SWITCH,
 612     "break", BREAK,
 613     "case", CASE,
 614     "cout", COUT,
 615     "cin", CIN,
 616     "endl", ENDL,
 617     "default", DEFAULT,
 618     "continue", CONTINUE,
 619     "true", TRUE,
 620     "false", FALSE,
 621     "", END  // mark end of table
 622 };
 623 
 624 //eval_exp不根據之前讀到的信息來操作, 是在eval_exp函數里面, 讀到什么就調用相應的處理過程.
 625 // Entry point into parser.
 626 void eval_exp(anonymous_var &value)
 627 {
 628     get_token();
 629 
 630     if(!*token)
 631     {
 632         throw InterpExc(NO_EXP);
 633     }
 634 
 635     //對於空語句給予一個默認的設置.
 636     if(*token == ';')
 637     {
 638         value.var_type = BOOL; // empty expression
 639         value.int_value = false;
 640         return;
 641     }
 642 
 643     eval_exp0(value);
 644 
 645 
 646     //這里會把處理完之后讀出來的token再返回去.
 647     putback(); // return last token read to input stream
 648 }
 649 
 650 
 651 // Process an assignment expression.
 652 void eval_exp0(anonymous_var &value)
 653 {
 654     // temp holds name of var receiving the assignment.
 655     char temp[MAX_ID_LEN + 1];
 656 
 657     tok_types temp_tok;
 658 
 659     if(token_type == IDENTIFIER)
 660     {
 661         if(is_var(token))   // if a var, see if assignment
 662         {
 663             strcpy(temp, token);
 664             temp_tok = token_type;
 665             get_token();
 666             if(*token == '=')   // is an assignment
 667             {
 668                 get_token();
 669                 eval_exp0(value); // get value to assign
 670 
 671                 assign_var(temp, value); // assign the value
 672 
 673                 return;
 674             }
 675             else   // not an assignment
 676             {
 677                 putback(); // restore original token
 678                 strcpy(token, temp);
 679                 token_type = temp_tok;
 680             }
 681         }
 682     }
 683     eval_exp1(value);
 684 }
 685 
 686 // Process relational operators.
 687 void eval_exp1(anonymous_var &value)
 688 {
 689     anonymous_var partial_value;
 690     char op;
 691     char relops[] =
 692     {
 693         LT, LE, GT, GE, EQ, NE, 0
 694     };
 695 
 696     eval_exp2(value);
 697 
 698     op = *token;
 699     if(strchr(relops, op))
 700     {
 701         get_token();
 702         eval_exp2(partial_value);
 703 
 704         switch(op)   // perform the relational operation
 705         {
 706         case LT:
 707         {
 708             int res = cmp(value, partial_value);
 709             value.var_type = BOOL;
 710             value.int_value = res < 0;
 711             break;
 712         }
 713         case LE:
 714         {
 715             int res = cmp(value, partial_value);
 716             value.var_type = BOOL;
 717             value.int_value = res <= 0;
 718             break;
 719         }
 720         case GT:
 721         {
 722             int res = cmp(value, partial_value);
 723             value.var_type = BOOL;
 724             value.int_value = res > 0;
 725             break;
 726         }
 727         case GE:
 728         {
 729             int res = cmp(value, partial_value);
 730             value.var_type = BOOL;
 731             value.int_value = res >= 0;
 732             break;
 733         }
 734         case EQ:
 735         {
 736             int res = cmp(value, partial_value);
 737 
 738             value.var_type = BOOL;
 739             value.int_value = (res == 0);
 740             break;
 741         }
 742         case NE:
 743         {
 744             int res = cmp(value, partial_value);
 745             value.var_type = BOOL;
 746             value.int_value = !(res == 0);
 747             break;
 748         }
 749         }
 750     }
 751 }
 752 
 753 // Add or subtract two terms.
 754 void eval_exp2(anonymous_var &value)
 755 {
 756     char  op;
 757     anonymous_var partial_value;
 758     char okops[] =
 759     {
 760         '(', INC, DEC, '-', '+', 0
 761     };
 762 
 763     eval_exp3(value);
 764 
 765     while((op = *token) == '+' || op == '-')
 766     {
 767         get_token();
 768 
 769         if(token_type == DELIMITER &&
 770                 !strchr(okops, *token))
 771             throw InterpExc(SYNTAX);
 772 
 773         eval_exp3(partial_value);
 774 
 775 
 776 
 777         switch(op)   // add or subtract
 778         {
 779         case '-':
 780         {
 781             value = sub(value, partial_value);
 782             break;
 783         }
 784         case '+':
 785         {
 786             value = add(value, partial_value);
 787             break;
 788         }
 789         }
 790     }
 791 }
 792 
 793 // Multiply or divide two factors.
 794 void eval_exp3(anonymous_var &value)
 795 {
 796     char  op;
 797     anonymous_var partial_value;
 798     char okops[] =
 799     {
 800         '(', INC, DEC, '-', '+', 0
 801     };
 802 
 803     eval_exp4(value);
 804 
 805     while((op = *token) == '*' || op == '/'
 806             || op == '%')
 807     {
 808         get_token();
 809 
 810         if(token_type == DELIMITER &&
 811                 !strchr(okops, *token))
 812             throw InterpExc(SYNTAX);
 813 
 814         eval_exp4(partial_value);
 815 
 816         switch(op)   // mul, div, or modulus
 817         {
 818         case '*':
 819         {
 820             value = mul(value, partial_value);
 821             break;
 822         }
 823 
 824         case '/':
 825         {
 826             //判斷除零異常在程序里面做了
 827             value = div(value, partial_value);
 828             break;
 829         }
 830         case '%':
 831         {
 832             anonymous_var tmp = div(value, partial_value);
 833             tmp = mul(partial_value, tmp);
 834             value = sub(value, tmp);
 835             break;
 836         }
 837         }
 838     }
 839 }
 840 
 841 // Is a unary +, -, ++, or --.
 842 void eval_exp4(anonymous_var &value)
 843 {
 844     char  op;
 845     char temp;
 846 
 847     op = '\0';
 848     if(*token == '+' || *token == '-' ||
 849             *token == INC || *token == DEC)
 850     {
 851         temp = *token;
 852         op = *token;
 853         get_token();
 854         value = find_var(token);
 855         //處理前綴++, --要把變化反應到變量身上.
 856         if(temp == INC)
 857         {
 858             anonymous_var tmp_var;
 859             tmp_var.int_value = 1;
 860             tmp_var.var_type = value.var_type;
 861             value = add(value, tmp_var);
 862             assign_var(token, value);
 863             get_token();
 864             return;
 865         }
 866         if(temp == DEC)
 867         {
 868             anonymous_var tmp_var;
 869             tmp_var.int_value = 1;
 870             tmp_var.var_type = value.var_type;
 871             value = add(value, tmp_var);
 872             assign_var(token, value);
 873             get_token();
 874             return;
 875         }
 876     }
 877 
 878     eval_exp5(value);
 879     if(op == '-')
 880     {
 881         neg_var(value);
 882     }
 883 }
 884 
 885 // Process parenthesized expression.
 886 void eval_exp5(anonymous_var &value)
 887 {
 888     if((*token == '('))
 889     {
 890         get_token();
 891 
 892         eval_exp0(value); // get subexpression
 893 
 894         if(*token != ')')
 895             throw InterpExc(PAREN_EXPECTED);
 896         get_token();
 897     }
 898     else
 899         atom(value);
 900 }
 901 
 902 // Find value of number, variable, or function.
 903 //增加一個處理功能, 處理浮點數, 但目前只允許***.***的形式, 不允許科學技術法.
 904 void atom(anonymous_var &value)
 905 {
 906     int i;
 907     char temp[MAX_ID_LEN + 1];
 908 
 909     switch(token_type)
 910     {
 911     case IDENTIFIER:
 912         i = internal_func(token);
 913         if(i != -1)
 914         {
 915             // Call "standard library" function.
 916             value = ((*intern_func[i].p)());
 917         }
 918         else if(find_func(token))
 919         {
 920             // Call programmer-created function.
 921             call();
 922             value = ret_value;//目前函數還只支持int返回值
 923         }
 924         else
 925         {
 926 
 927             //在這里處理了后綴++, --
 928             value = find_var(token); // get var's value
 929             strcpy(temp, token); // save variable name
 930 
 931             // Check for ++ or --.
 932             get_token();
 933             if(*token == INC || *token == DEC)
 934             {
 935                 anonymous_var tmp_val = find_var(temp);
 936                 value = tmp_val;
 937                 if(*token == INC)
 938                 {
 939                     anonymous_var one;
 940                     one.int_value = 1;
 941                     one.var_type = tmp_val.var_type;
 942                     tmp_val = add(tmp_val, one);
 943                     assign_var(temp, tmp_val);
 944                 }
 945                 else
 946                 {
 947                     anonymous_var one;
 948                     one.int_value = 1;
 949                     one.var_type = tmp_val.var_type;
 950                     tmp_val = sub(tmp_val, one);
 951                     assign_var(temp, tmp_val);
 952                 }
 953 
 954             }
 955             else putback();
 956         }
 957 
 958         get_token();
 959         return;
 960     case NUMBER: // is numeric constant
 961         //這里對浮點和整型類型做個判斷
 962         if(strchr(token, '.'))
 963         {
 964 
 965             value.var_type = DOUBLE;
 966             value.float_value = atof(token);
 967         }
 968         else
 969         {
 970             value.var_type = INT;
 971             value.int_value = atoi(token);
 972         }
 973         get_token();
 974 
 975         return;
 976 
 977         //char constant
 978     case DELIMITER: // see if character constant
 979         if(*token == '\'')
 980         {
 981             value.var_type = CHAR;
 982             value.int_value = *prog;
 983             prog++;
 984             if(*prog != '\'')
 985                 throw InterpExc(QUOTE_EXPECTED);
 986 
 987             prog++;
 988             get_token();
 989 
 990             return ;
 991         }
 992         if(*token == ')') return; // process empty expression
 993         else throw InterpExc(SYNTAX);  // otherwise, syntax error
 994     case KEYWORD:
 995     {
 996         if(0 == strcmp(token, "true"))
 997         {
 998             //cout << "jackieddddd" << endl;
 999             value.var_type = BOOL;
1000             value.int_value = 1;
1001         }
1002         else if(0 == strcmp(token, "false"))
1003         {
1004             value.var_type = BOOL;
1005             value.int_value = 0;
1006         }
1007         else
1008         {
1009             throw InterpExc(SYNTAX);
1010         }
1011         get_token();
1012         break;
1013     }
1014     default:
1015         throw InterpExc(SYNTAX); // syntax error
1016     }
1017 }
1018 
1019 // Display an error message.
1020 void sntx_err(error_msg error)
1021 {
1022     char *p, *temp;
1023     int linecount = 0;
1024 
1025     static char *e[] = //這里的顯示信息, 是跟頭文件里面定義的錯誤flag順序一致的
1026     {
1027         "Syntax error",
1028         "No expression present",
1029         "Not a variable",
1030         "Duplicate variable name",
1031         "Duplicate function name",
1032         "Semicolon expected",
1033         "Unbalanced braces",
1034         "Function undefined",
1035         "Type specifier expected",
1036         "Return without call",
1037         "Parentheses expected",
1038         "While expected",
1039         "Closing quote expected",
1040         "Division by zero",
1041         "{ expected (control statements must use blocks)",
1042         "Colon expected",
1043         "Unsupported type yet",
1044     };
1045 
1046     // Display error and line number.
1047     cout << "\n" << e[error];
1048     p = p_buf;
1049     while(p != prog)   // find line number of error
1050     {
1051         p++;
1052         if(*p == '\r')
1053         {
1054             linecount++;
1055         }
1056     }
1057     cout << " in line " << linecount << endl;
1058 
1059     temp = p;
1060     while(p > p_buf && *p != '\n') p--;
1061 
1062     // Display offending line.
1063     while(p <= temp)
1064         cout << *p++;
1065 
1066     cout << endl;
1067 }
1068 
1069 // Get a token.
1070 tok_types get_token()
1071 {
1072     char *temp;
1073 
1074     token_type = UNDEFTT;
1075     tok = UNDEFTOK;
1076 
1077     temp = token;
1078     *temp = '\0';
1079 
1080     // Skip over white space.
1081     while(isspace(*prog) && *prog) ++prog;
1082 
1083     // Skip over newline.
1084     while(*prog == '\r')
1085     {
1086         ++prog;
1087         ++prog;
1088         // Again, skip over white space.
1089         while(*prog && isspace(*prog)) ++prog;
1090     }
1091 
1092     // Check for end of program.
1093     if(*prog == '\0')
1094     {
1095         *token = '\0';
1096         tok = END;
1097         return (token_type = DELIMITER);
1098     }
1099 
1100     // Check for block delimiters.
1101     if(strchr("{}", *prog))
1102     {
1103         *temp = *prog;
1104         temp++;
1105         *temp = '\0';
1106         prog++;
1107         return (token_type = BLOCK);
1108     }
1109 
1110     // Look for comments.
1111     if(*prog == '/')
1112         if(*(prog + 1) == '*') // is a /* comment
1113         {
1114             prog += 2;
1115 
1116             //這個循環很給力
1117             do   // find end of comment
1118             {
1119                 while(*prog != '*') prog++;
1120                 prog++;
1121             }
1122             while (*prog != '/');
1123             prog++;
1124             return (token_type = DELIMITER);
1125         }
1126         else if(*(prog + 1) == '/')   // is a // comment
1127         {
1128             prog += 2;
1129             // Find end of comment.
1130             while(*prog != '\r' && *prog != '\0') prog++;
1131             if(*prog == '\r') prog += 2;
1132             return (token_type = DELIMITER);
1133         }
1134 
1135     // Check for double-ops.
1136     if(strchr("!<>=+-", *prog))
1137     {
1138         switch(*prog)
1139         {
1140         case '=':
1141             if(*(prog + 1) == '=')
1142             {
1143                 prog++;
1144                 prog++;
1145                 *temp = EQ;
1146                 temp++;
1147                 *temp = EQ;
1148                 temp++;
1149                 *temp = '\0';
1150             }
1151             break;
1152         case '!':
1153             if(*(prog + 1) == '=')
1154             {
1155                 prog++;
1156                 prog++;
1157                 *temp = NE;
1158                 temp++;
1159                 *temp = NE;
1160                 temp++;
1161                 *temp = '\0';
1162             }
1163             break;
1164         case '<':
1165             if(*(prog + 1) == '=')
1166             {
1167                 prog++;
1168                 prog++;
1169                 *temp = LE;
1170                 temp++;
1171                 *temp = LE;
1172             }
1173             else if(*(prog + 1) == '<')
1174             {
1175                 prog++;
1176                 prog++;
1177                 *temp = LS;
1178                 temp++;
1179                 *temp = LS;
1180             }
1181             else
1182             {
1183                 prog++;
1184                 *temp = LT;
1185             }
1186             temp++;
1187             *temp = '\0';
1188             break;
1189         case '>':
1190             if(*(prog + 1) == '=')
1191             {
1192                 prog++;
1193                 prog++;
1194                 *temp = GE;
1195                 temp++;
1196                 *temp = GE;
1197             }
1198             else if(*(prog + 1) == '>')
1199             {
1200                 prog++;
1201                 prog++;
1202                 *temp = RS;
1203                 temp++;
1204                 *temp = RS;
1205             }
1206             else
1207             {
1208                 prog++;
1209                 *temp = GT;
1210             }
1211             temp++;
1212             *temp = '\0';
1213             break;
1214         case '+':
1215             if(*(prog + 1) == '+')
1216             {
1217                 prog++;
1218                 prog++;
1219                 *temp = INC;
1220                 temp++;
1221                 *temp = INC;
1222                 temp++;
1223                 *temp = '\0';
1224             }
1225             break;
1226         case '-':
1227             if(*(prog + 1) == '-')
1228             {
1229                 prog++;
1230                 prog++;
1231                 *temp = DEC;
1232                 temp++;
1233                 *temp = DEC;
1234                 temp++;
1235                 *temp = '\0';
1236             }
1237             break;
1238         }
1239 
1240         if(*token) return(token_type = DELIMITER);
1241     }
1242 
1243     // Check for other delimiters.
1244     if(strchr("+-*^/%=;:(),'", *prog))
1245     {
1246         *temp = *prog;
1247         prog++;
1248         temp++;
1249         *temp = '\0';
1250         return (token_type = DELIMITER);
1251     }
1252 
1253     // Read a quoted string.
1254     if(*prog == '"')
1255     {
1256         prog++;
1257         while(*prog != '"' && *prog != '\r' && *prog)
1258         {
1259             // Check for \n escape sequence.
1260             if(*prog == '\\')
1261             {
1262                 if(*(prog + 1) == 'n')
1263                 {
1264                     prog++;
1265                     *temp++ = '\n';
1266                 }
1267             }
1268             else if((temp - token) < MAX_T_LEN)
1269                 *temp++ = *prog;
1270 
1271             prog++;
1272         }
1273         if(*prog == '\r' || *prog == 0)
1274             throw InterpExc(SYNTAX);
1275         prog++;
1276         *temp = '\0';
1277         return (token_type = STRING);
1278     }
1279 
1280     // Read an integer number, or float
1281     //由於現在還沒加入結構體和類, 所以直接這樣判斷'.'還是可以的, 不過會有隱患, 要記得~
1282     if(isdigit(*prog) || *prog == '.')
1283     {
1284         while(!isdelim(*prog)) //這樣判斷安全嗎?
1285         {
1286             if((temp - token) < MAX_ID_LEN)
1287                 *temp++ = *prog;
1288             prog++;
1289         }
1290         *temp = '\0';
1291         return (token_type = NUMBER);
1292     }
1293 
1294     // Read identifier or keyword.
1295     if(isalpha(*prog))
1296     {
1297         while(!isdelim(*prog))
1298         {
1299             if((temp - token) < MAX_ID_LEN)
1300                 *temp++ = *prog;
1301             prog++;
1302         }
1303         token_type = TEMP;
1304     }
1305 
1306     *temp = '\0';
1307 
1308     // Determine if token is a keyword or identifier.
1309     if(token_type == TEMP)
1310     {
1311         tok = look_up(token); // convert to internal form
1312         if(tok) token_type = KEYWORD; // is a keyword
1313         else token_type = IDENTIFIER;
1314     }
1315 
1316     // Check for unidentified character in file.
1317     if(token_type == UNDEFTT)
1318         throw InterpExc(SYNTAX);
1319 
1320     return token_type;
1321 }
1322 
1323 // Return a token to input stream.
1324 void putback()
1325 {
1326     char *t;
1327 
1328     t = token;
1329     for(; *t; t++) prog--;
1330 }
1331 
1332 // Look up a token's internal representation in the
1333 // token table.
1334 token_ireps look_up(char *s)
1335 {
1336     int i;
1337 
1338     //C++本來就區分大小寫的, 為什么還給程序轉化..
1339     //char *p;
1340 
1341     //// Convert to lowercase.
1342     //p = s;
1343     //while(*p)
1344     //{
1345     //    *p = tolower(*p);
1346     //    p++;
1347     //}
1348 
1349     // See if token is in table.
1350     for(i = 0; *com_table[i].command; i++)
1351     {
1352         if(!strcmp(com_table[i].command, s))
1353             return com_table[i].tok;
1354     }
1355 
1356     return UNDEFTOK; // unknown command
1357 }
1358 
1359 // Return index of internal library function or -1 if
1360 // not found.
1361 int internal_func(char *s)
1362 {
1363     int i;
1364 
1365     for(i = 0; intern_func[i].f_name[0]; i++)
1366     {
1367         if(!strcmp(intern_func[i].f_name, s))  return i;
1368     }
1369     return -1;
1370 }
1371 
1372 // Return true if c is a delimiter.
1373 bool isdelim(char c)
1374 {
1375     if(strchr(" !:;,+-<>'/*%^=()", c) || c == 9 ||
1376             c == '\r' || c == 0) return true;
1377     return false;
1378 }
1379 
1380 
1381 
1382 
1383 /***********************************************************************
1384 minicpp.cpp 主函數在這里, 對於for, if while switch等的實現也寫在了這里.
1385 ************************************************************************/
1386 #include <iostream>
1387 #include <fstream>
1388 #include <new>
1389 #include <stack>
1390 #include <vector>
1391 #include <cstring>
1392 #include <cstdlib>
1393 #include <cctype>
1394 #include "mccommon.h"
1395 
1396 using namespace std;
1397 
1398 char *prog;  // current execution point in source code
1399 char *p_buf; // points to start of program buffer
1400 
1401 // This vector holds info for global variables.
1402 vector<var> global_vars;
1403 
1404 // This vector holds info for local variables
1405 // and parameters.
1406 vector<var> local_var_stack;
1407 
1408 // This vector holds info about functions.
1409 vector<func_type> func_table;
1410 
1411 // Stack for managing function scope.
1412 
1413 stack<int> func_call_stack;
1414 
1415 // Stack for managing nested scopes.
1416 //整形的棧, 存儲的是本函數壓棧之前棧的大小.
1417 stack<int> nest_scope_stack;
1418 
1419 char token[MAX_T_LEN + 1]; // current token
1420 tok_types token_type; // token type
1421 token_ireps tok; // internal representation
1422 
1423 anonymous_var ret_value; // function return value
1424 
1425 bool breakfound = false; // true if break encountered
1426 bool continuefound = false;
1427 
1428 
1429 
1430 
1431 int main(int argc, char *argv[])
1432 {
1433     if(argc != 2)
1434     {
1435         cout << "Usage: minicpp <filename>\n";
1436         return 1;
1437     }
1438 
1439     // Allocate memory for the program.
1440     try
1441     {
1442         p_buf = new char[PROG_SIZE];
1443     }
1444     catch (bad_alloc exc)
1445     {
1446         cout << "Could Not Allocate Program Buffer\n";
1447         return 1;
1448     }
1449 
1450     // Load the program to execute.
1451     if(!load_program(p_buf, argv[1])) return 1;
1452 
1453     // Set program pointer to start of program buffer.
1454     prog = p_buf;
1455 
1456     try
1457     {
1458         // Find the location of all functions
1459         // and global variables in the program.
1460         prescan();
1461 
1462         // Next, set up the call to main().
1463 
1464         // Find program starting point.
1465         prog = find_func("main");
1466 
1467         // Check for incorrect or missing main() function.
1468         if(!prog)
1469         {
1470             cout << "main() Not Found\n";
1471             return 1;
1472         }
1473 
1474         // Back up to opening (.
1475         prog--;
1476 
1477         // Set the first token to main
1478         strcpy(token, "main");
1479 
1480         // Call main() to start interpreting.
1481         call();
1482     }
1483     catch(InterpExc exc)
1484     {
1485         sntx_err(exc.get_err());
1486         return 1;
1487     }
1488     catch(bad_alloc exc)
1489     {
1490         cout << "Out Of Memory\n";
1491         return 1;
1492     }
1493 
1494     return ret_value.int_value;
1495 }
1496 
1497 // Load a program.
1498 bool load_program(char *p, char *fname)
1499 {
1500     int i = 0;
1501 
1502     ifstream in(fname, ios::in | ios::binary);
1503     if(!in)
1504     {
1505         cout << "Cannot Open file.\n";
1506         return false;
1507     }
1508 
1509     do
1510     {
1511         *p = in.get();
1512         p++;
1513         i++;
1514     }
1515     while(!in.eof() && i < PROG_SIZE);
1516 
1517     if(i == PROG_SIZE)
1518     {
1519         cout << "Program Too Big\n";
1520         return false;
1521     }
1522 
1523     // Null terminate the program. Skip any EOF
1524     // mark if present in the file.
1525     if(*(p - 2) == 0x1a) *(p - 2) = '\0';
1526     else *(p - 1) = '\0';
1527 
1528     in.close();
1529 
1530     return true;
1531 }
1532 
1533 // Find the location of all functions in the program
1534 // and store global variables.
1535 void prescan()
1536 {
1537     char *p, *tp;
1538     char temp[MAX_ID_LEN + 1];
1539     token_ireps datatype;
1540     func_type ft;
1541 
1542     // When brace is 0, the current source position
1543     // is outside of any function.
1544     int brace = 0;
1545 
1546     p = prog;
1547 
1548     do
1549     {
1550         // Bypass code inside functions, brace==0, 保證了現在是在全局作用域
1551         while(brace)
1552         {
1553             get_token();
1554             if(tok == END) throw InterpExc(UNBAL_BRACES);
1555             if(*token == '{') brace++;
1556             if(*token == '}') brace--;
1557         }
1558 
1559         tp = prog; // save current position
1560         get_token();
1561 
1562         // See if global var type or function return type.
1563         if(is_valid_type(tok))
1564         {
1565             datatype = tok; // save data type
1566             get_token();
1567 
1568             if(token_type == IDENTIFIER)
1569             {
1570                 strcpy(temp, token);
1571                 get_token();
1572 
1573                 if(*token != '(')   // must be global var
1574                 {
1575                     prog = tp; // return to start of declaration
1576                     decl_global();
1577                 }
1578                 else if(*token == '(')   // must be a function
1579                 {
1580 
1581                     // See if function already defined.
1582                     for(unsigned i = 0; i < func_table.size(); i++)
1583                         if(!strcmp(func_table[i].func_name, temp))
1584                             throw InterpExc(DUP_FUNC);
1585 
1586                     ft.loc = prog;
1587                     ft.ret_type = datatype;
1588                     strcpy(ft.func_name, temp);
1589                     func_table.push_back(ft);
1590 
1591                     do
1592                     {
1593                         get_token();
1594                     }
1595                     while(*token != ')');
1596                     // Next token will now be opening curly
1597                     // brace of function.
1598                 }
1599                 else putback();
1600             }
1601         }
1602         else
1603         {
1604             if(*token == '{') brace++;
1605             if(*token == '}') brace--;
1606         }
1607     }
1608     while(tok != END);
1609     if(brace) throw InterpExc(UNBAL_BRACES);
1610     prog = p;
1611 }
1612 
1613 // Interpret a single statement or block of code. When
1614 // interp() returns from its initial call, the final
1615 // brace (or a return) in main() has been encountered.
1616 
1617 //對於interp我做了一個小改動, 如果執行語句里面有break, 那么就在推出interp之前讓程序把整個block的代碼都走一遍, 但是不執行了
1618 //這樣, 以后調用interp的程序就不用再為break后面的語句做清理工作了.
1619 //在interp里面, 遇到{}會產生一個新的名字空間, 遇到int 和char還會declare一個local變量
1620 void interp()
1621 {
1622     anonymous_var value;
1623     int block = 0;
1624     char *tmp_prog = NULL;
1625     //break語句會對外面的控制流程造成影響, 但是continue不會, 它只會不讓本次循環后面的語句不執行.
1626     //但是還是要維護一個全局的continue, 因為本block需要知道子block里面是不是有continue;
1627     do
1628     {
1629         if(breakfound || continuefound)
1630         {
1631 
1632             //如果這是個{}包含的塊, 那么就用find_eob把整個塊吃掉
1633             if(block && tmp_prog)
1634             {
1635 
1636                 prog = tmp_prog;
1637                 find_eob();
1638             }
1639             else
1640             {
1641                 //對於知識一條語句的塊, 在break跳出之前吃掉這個分號
1642                 get_token();
1643 
1644             }
1645             return;
1646         }
1647 
1648         token_type = get_token();
1649         //對於那些exec_while, exec_while那個向前看的token是在這里讀出來的
1650         //跟eval_exp沒有關系.
1651 
1652         // See what kind of token is up.
1653         if(token_type == IDENTIFIER ||
1654                 *token == INC || *token == DEC)
1655         {
1656             // Not a keyword, so process expression.
1657             putback();  // restore token to input stream for
1658             // further processing by eval_exp()
1659             eval_exp(value); // process the expression
1660             //eval_exp和exec_while是相同的層次, 在interp看到向前看字符的時候, 就會遞歸調用相應的過程.
1661             if(*token != ';') throw InterpExc(SEMI_EXPECTED);
1662         }
1663         else if(token_type == BLOCK) // block delimiter?
1664         {
1665             if(*token == '{')   // is a block
1666             {
1667                 putback();
1668                 tmp_prog = prog;
1669                 get_token();
1670                 block = 1; // interpreting block, not statement
1671                 // Record nested scope.
1672                 nest_scope_stack.push(local_var_stack.size());
1673                 //nest_scope_stack里面存的是上一個block的stack的位置,
1674                 //用戶恢復棧.
1675             }
1676             else   // is a }, so reset scope and return
1677             {
1678                 // Reset nested scope.
1679                 local_var_stack.resize(nest_scope_stack.top());
1680                 nest_scope_stack.pop();
1681                 return;
1682             }
1683         }
1684         else if(is_valid_type(tok))
1685         {
1686             putback();
1687             decl_local();
1688         }
1689         else // is keyword
1690             switch(tok)
1691             {
1692             case RETURN:  // return from function call, 不要在這里清理局部作用域了, call里面做了處理.
1693                 /*if(block)
1694                 {
1695                     local_var_stack.resize(nest_scope_stack.top());
1696                     nest_scope_stack.pop();
1697                 }*/
1698                 func_ret();
1699                 return;
1700             case IF:      // process an if statement
1701                 exec_if();
1702                 break;
1703             case ELSE:    // process an else statement
1704                 find_eob(); // find end of else block
1705                 // and continue execution
1706                 break;
1707             case WHILE:   // process a while loop
1708                 exec_while();
1709                 break;
1710             case DO:      // process a do-while loop
1711                 exec_do();
1712                 break;
1713             case FOR:     // process a for loop
1714                 exec_for();
1715 
1716                 break;
1717             case BREAK:   // handle break
1718                 breakfound = true;
1719                 // Reset nested scope.
1720                 //這里要特判一下是不是從一個block里面的break, 因為在我修改之后, for while的循環體現在可以是
1721                 //一個單個的語句了
1722                 if(block)
1723                 {
1724                     local_var_stack.resize(nest_scope_stack.top());
1725                     nest_scope_stack.pop();
1726                 }
1727                 break;
1728             case CONTINUE:
1729             {
1730                 continuefound = true;
1731                 if(block)
1732                 {
1733                     local_var_stack.resize(nest_scope_stack.top());
1734                     nest_scope_stack.pop();
1735                 }
1736                 break;
1737             }
1738             case SWITCH:  // handle a switch statement
1739                 exec_switch();
1740                 break;
1741             case COUT:    // handle console output
1742                 exec_cout();
1743                 //cout << "breakfuond :" << breakfound << endl;
1744                 break;
1745             case CIN:     // handle console input
1746                 exec_cin();
1747                 break;
1748             case END:
1749                 exit(0);
1750 
1751             }
1752     }
1753     while (tok != END && block);
1754     return;
1755 }
1756 
1757 
1758 //可以使用map優化.
1759 // Return the entry point of the specified function.
1760 // Return NULL if not found.
1761 char *find_func(char *name)
1762 {
1763     unsigned i;
1764 
1765     for(i = 0; i < func_table.size(); i++)
1766         if(!strcmp(name, func_table[i].func_name))
1767             return func_table[i].loc;
1768 
1769     return NULL;
1770 }
1771 
1772 // Declare a global variable.
1773 void decl_global()
1774 {
1775     token_ireps vartype;
1776     var v;
1777 
1778     get_token(); // get type
1779 
1780     vartype = tok; // save var type
1781 
1782     anonymous_var value;
1783 
1784     // Process comma-separated list.
1785     do
1786     {
1787         v.value.var_type = vartype;
1788         init_var(v.value); // init to 0
1789         get_token(); // get name
1790 
1791         // See if variable is a duplicate.
1792         for(unsigned i = 0; i < global_vars.size(); i++)
1793             if(!strcmp(global_vars[i].var_name, token))
1794                 throw InterpExc(DUP_VAR);
1795 
1796         strcpy(v.var_name, token);
1797         global_vars.push_back(v);
1798 
1799         putback();
1800         eval_exp(value); //這個eval_exp會實現賦值, 這里value只是個啞元, 我們不用
1801 
1802         get_token();
1803 
1804     }
1805     while(*token == ',');
1806 
1807     if(*token != ';') throw InterpExc(SEMI_EXPECTED);
1808 }
1809 
1810 // Declare a local variable.
1811 void decl_local()
1812 {
1813     var v;
1814 
1815     get_token(); // get var type
1816     v.value.var_type = tok; // store type
1817 
1818     init_var(v.value); // init var to 0, 對局部變量也直接初始化成0了..
1819     anonymous_var value;
1820 
1821     // Process comma-separated list.
1822     do
1823     {
1824         get_token(); // get var name
1825 
1826         // See if variable is already the name
1827         // of a local variable in this scope.
1828         if(!local_var_stack.empty())
1829             for(int i = local_var_stack.size() - 1;
1830                     i >= nest_scope_stack.top(); i--)
1831             {
1832                 if(!strcmp(local_var_stack[i].var_name, token))
1833                     throw InterpExc(DUP_VAR);
1834             }
1835 
1836         strcpy(v.var_name, token);
1837         local_var_stack.push_back(v);
1838         putback();
1839         eval_exp(value);//這個eval_exp會實現賦值, 這里value只是個啞元, 我們不用
1840         get_token();
1841     }
1842     while(*token == ',');
1843 
1844     if(*token != ';') throw InterpExc(SEMI_EXPECTED);
1845 }
1846 
1847 // Call a function.
1848 void call()
1849 {
1850     char *loc, *temp;
1851     int lvartemp;
1852 
1853     // First, find entry point of function.
1854     loc = find_func(token);
1855 
1856     if(loc == NULL)
1857         throw InterpExc(FUNC_UNDEF); // function not defined
1858     else
1859     {
1860         // Save local var stack index.
1861         lvartemp = local_var_stack.size();
1862 
1863         //get_args 和get_params先后調用 , 進行了一下替換
1864         get_args(); // get function arguments
1865         temp = prog; // save return location
1866 
1867         func_call_stack.push(lvartemp); // push local var index
1868 
1869         prog = loc; // reset prog to start of function
1870         get_params(); // load the function's parameters with
1871         // the values of the arguments
1872 
1873         interp(); // interpret the function
1874 
1875         prog = temp; // reset the program pointer
1876 
1877         if(func_call_stack.empty()) throw InterpExc(RET_NOCALL);
1878 
1879         // Reset local_var_stack to its previous state.
1880 
1881         //這里的resize會把后面的剛剛壓入棧的變量刪掉.
1882         local_var_stack.resize(func_call_stack.top());
1883         func_call_stack.pop();
1884     }
1885 }
1886 
1887 // Push the arguments to a function onto the local
1888 // variable stack.
1889 void get_args()
1890 {
1891     anonymous_var value, temp[NUM_PARAMS];
1892     int count = 0;
1893     var vt;
1894 
1895     count = 0;
1896     get_token();
1897     if(*token != '(') throw InterpExc(PAREN_EXPECTED);
1898 
1899     // Process a comma-separated list of values.
1900     do
1901     {
1902         eval_exp(value);
1903         temp[count] = value; // save temporarily
1904         get_token();
1905         count++;
1906     }
1907     while(*token == ',');
1908     count--;
1909 
1910     // Now, push on local_var_stack in reverse order.
1911     for(; count >= 0; count--)
1912     {
1913         vt.value = temp[count];
1914         local_var_stack.push_back(vt);
1915     }
1916 }
1917 
1918 // Get function parameters.
1919 
1920 //在這個函數里面實現了從實參到形參的轉化工作, 不錯.
1921 void get_params()
1922 {
1923     var *p;
1924     int i;
1925 
1926     i = local_var_stack.size() - 1;
1927 
1928     // Process comma-separated list of parameters.
1929     do
1930     {
1931         get_token();
1932         p = &local_var_stack[i];
1933         if(*token != ')' )
1934         {
1935             if(is_valid_type(tok))
1936                 throw InterpExc(TYPE_EXPECTED);
1937 
1938             p->value.var_type = tok;
1939             get_token();
1940 
1941             // Link parameter name with argument already on
1942             // local var stack.
1943             strcpy(p->var_name, token);
1944             get_token();
1945             i--;
1946         }
1947         else break;
1948     }
1949     while(*token == ',');
1950 
1951     //在這里判了一下, 看最后一個讀到的是不是')'
1952     if(*token != ')') throw InterpExc(PAREN_EXPECTED);
1953 }
1954 
1955 // Return from a function.
1956 void func_ret()
1957 {
1958     anonymous_var value;
1959 
1960     //value = 0;
1961 
1962     // Get return value, if any.
1963     //目前設定是只支持int返回值.
1964     eval_exp(value);
1965 
1966     ret_value = value;
1967 }
1968 
1969 // Assign a value to a variable.
1970 void assign_var(char *vname, anonymous_var value)
1971 {
1972     //cout << "assign_var" << endl;
1973     // First, see if it's a local variable.
1974     if(!local_var_stack.empty())
1975         for(int i = local_var_stack.size() - 1;
1976                 i >= func_call_stack.top(); i--)
1977         {
1978             if(!strcmp(local_var_stack[i].var_name,
1979                        vname))
1980             {
1981                 adaptive_assign_var(local_var_stack[i].value, value);
1982                 return;
1983             }
1984         }
1985 
1986     // Otherwise, try global vars.
1987     for(unsigned i = 0; i < global_vars.size(); i++)
1988         if(!strcmp(global_vars[i].var_name, vname))
1989         {
1990             adaptive_assign_var(global_vars[i].value, value);
1991             //cout << value.float_value << " >>>" << endl;
1992             return;
1993         }
1994 
1995     throw InterpExc(NOT_VAR); // variable not found
1996 }
1997 
1998 // Find the value of a variable.
1999 anonymous_var find_var(char *vname)
2000 {
2001     // First, see if it's a local variable.
2002     if(!local_var_stack.empty())
2003         for(int i = local_var_stack.size() - 1;
2004                 i >= func_call_stack.top(); i--)
2005         {
2006             if(!strcmp(local_var_stack[i].var_name, vname))
2007                 return local_var_stack[i].value;
2008         }
2009 
2010     // Otherwise, try global vars.
2011     for(unsigned i = 0; i < global_vars.size(); i++)
2012         if(!strcmp(global_vars[i].var_name, vname))
2013             return global_vars[i].value;
2014 
2015     throw InterpExc(NOT_VAR); // variable not found
2016 }
2017 
2018 
2019 //在處理if的時候也處理了else的模塊
2020 // Execute an if statement.
2021 void exec_if()
2022 {
2023     anonymous_var cond;
2024 
2025     eval_exp(cond); // get if expression.
2026 
2027     if(get_bool_val(cond))   // if true, process target of IF
2028     {
2029         // Confirm start of block.
2030 
2031         interp();
2032     }
2033     else
2034     {
2035         // Otherwise skip around IF block and
2036         // process the ELSE, if present.
2037 
2038         find_eob(); // find start of next line
2039         get_token();
2040 
2041         if(tok != ELSE)
2042         {
2043             // Restore token if no ELSE is present.
2044             putback();
2045             return;
2046         }
2047         // Confirm start of block.
2048         get_token();
2049 
2050         if(tok == IF)
2051         {
2052             exec_if();
2053             return;
2054         }
2055         putback();
2056         interp();
2057     }
2058 }
2059 
2060 // Execute a switch statement.
2061 void exec_switch()
2062 {
2063     anonymous_var sval, cval;
2064     int brace;
2065 
2066     eval_exp(sval); // Get switch expression.
2067 
2068     // Check for start of block.
2069     if(*token != '{')
2070         throw InterpExc(BRACE_EXPECTED);
2071 
2072     // Record new scope.
2073     nest_scope_stack.push(local_var_stack.size());
2074 
2075     // Now, check case statements.
2076     for(;;)
2077     {
2078         brace = 1;
2079         // Find a case statement.
2080         do
2081         {
2082             get_token();
2083             if(*token == '{') brace++;
2084             else if(*token == '}') brace--;
2085         }
2086         while(tok != CASE && tok != END && brace && tok != DEFAULT);
2087 
2088         // If no matching case found, then skip.
2089         if(!brace) break;
2090 
2091 
2092         if(tok == END) throw InterpExc(SYNTAX);
2093         if(tok == DEFAULT)
2094         {
2095             get_token();
2096             if(*token != ':')
2097                 throw InterpExc(COLON_EXPECTED);
2098             do
2099             {
2100                 interp();
2101                 get_token();
2102                 if(*token == '}')
2103                 {
2104                     putback();
2105                     break;
2106                 }
2107                 putback();
2108                 //if(*token == '{') brace++;
2109                 //else if(*token == '}') brace--;
2110             }
2111             while(!breakfound && tok != END);
2112 
2113             brace = 1;
2114 
2115             // Find end of switch statement.
2116             while(brace)
2117             {
2118                 get_token();
2119                 if(*token == '{') brace++;
2120                 else if(*token == '}') brace--;
2121             }
2122             breakfound = false;
2123 
2124             break;
2125 
2126         }
2127 
2128         // Get value of the case statement.
2129         eval_exp(cval);
2130 
2131         // Read and discard the :
2132         get_token();
2133 
2134         if(*token != ':')
2135             throw InterpExc(COLON_EXPECTED);
2136 
2137         // If values match, then interpret.
2138         if(0 == cmp(cval, sval))
2139         {
2140 
2141             do
2142             {
2143                 interp();
2144 
2145                 get_token();
2146                 if(*token == '}')
2147                 {
2148                     putback();
2149                     break;
2150                 }
2151                 putback();
2152             }
2153             while(!breakfound && tok != END && brace);
2154 
2155             brace = 1;
2156 
2157             // Find end of switch statement.
2158             while(brace)
2159             {
2160                 get_token();
2161                 if(*token == '{') brace++;
2162                 else if(*token == '}') brace--;
2163             }
2164             breakfound = false;
2165 
2166             break;
2167         }
2168     }
2169 }
2170 
2171 // Execute a while loop.
2172 //同下面的do while, 這個也會putback while
2173 void exec_while()
2174 {
2175     anonymous_var cond;
2176     char *temp;
2177 
2178     putback(); // put back the while
2179     temp = prog; // save location of top of while loop
2180 
2181     get_token();
2182     eval_exp(cond); // check the conditional expression
2183 
2184     if(get_bool_val(cond))
2185         interp(); // if true, interpret
2186     else   // otherwise, skip to end of loop
2187     {
2188         find_eob();
2189         return;
2190     }
2191     continuefound = false;
2192     if(!breakfound)
2193         prog = temp; // loop back to top
2194     else
2195     {
2196         breakfound = false;
2197         return;
2198     }
2199 }
2200 
2201 // Execute a do loop.
2202 
2203 //解釋: exec_do是在主函數讀到了do的時候才會調用, 因此
2204 //在exec_do調用的時候, do這個token已經被讀出來了,
2205 //而exec_do還想要在需要繼續執行的時候是prog復位到do, 那么就得在程序開始putback一下.
2206 void exec_do()
2207 {
2208     anonymous_var cond;
2209     char *temp;
2210 
2211     // Save location of top of do loop.
2212     putback(); // put back do
2213     temp = prog;
2214 
2215     get_token(); // get start of loop block
2216 
2217     // Confirm start of block.
2218     get_token();
2219     if(*token != '{')
2220         throw InterpExc(BRACE_EXPECTED);
2221     putback();
2222 
2223     interp(); // interpret loop
2224 
2225     // Check for break in loop.
2226     if(breakfound)
2227     {
2228         breakfound = false;
2229         get_token();
2230         if(tok != WHILE) throw InterpExc(WHILE_EXPECTED);
2231         eval_exp(cond); // check the loop condition
2232         return;
2233     }
2234     if(continuefound)
2235     {
2236         continuefound = false;
2237         prog = temp;
2238         return;
2239     }
2240 
2241     get_token();
2242     if(tok != WHILE) throw InterpExc(WHILE_EXPECTED);
2243 
2244     eval_exp(cond); // check the loop condition
2245 
2246     // If true loop; otherwise, continue on.
2247 
2248     if(get_bool_val(cond)) prog = temp;
2249 }
2250 
2251 // Execute a for loop.
2252 //但是for就不能像while和do while那樣, 在需要繼續循環的時候復位prog指針了, 因為for
2253 //復位的話, 初始點也跟着復位了, 就是for(int i= 0; i< 12; i++)里面的i也會變成0
2254 void exec_for()
2255 {
2256     anonymous_var cond;
2257     char *temp, *temp2;
2258     int paren ;
2259 
2260     //for_local用來標記是不是在for()內部定義了新變量, 如果是, 就會產生新的作用域
2261     bool for_local = false;
2262 
2263     get_token(); // skip opening (
2264     get_token();
2265 
2266     if(is_valid_type(tok))//當前讀入的token是個類型關鍵字, 這樣就會觸發一個局部作用域
2267     {
2268         putback();
2269         nest_scope_stack.push(local_var_stack.size());
2270         for_local = true;
2271         decl_local();
2272 
2273     }
2274     else
2275     {
2276         eval_exp(cond); // initialization expression
2277     }
2278 
2279     //這個是decl_local和eval_exp最后讀到的token, 已經被讀出來了
2280     if(*token != ';') throw InterpExc(SEMI_EXPECTED);
2281 
2282     prog++; // get past the ;
2283     temp = prog;
2284 
2285     for(;;)
2286     {
2287         // Get the value of the conditional expression.
2288         eval_exp(cond);
2289 
2290         if(*token != ';') throw InterpExc(SEMI_EXPECTED);
2291         prog++; // get past the ;
2292         temp2 = prog;
2293 
2294         // Find start of for block.
2295         paren = 1;
2296         while(paren)
2297         {
2298             get_token();
2299             if(*token == '(') paren++;
2300             if(*token == ')') paren--;
2301         }
2302 
2303 
2304         // If condition is true, interpret
2305         //現在從for()后面開始interpret
2306         //
2307         if(get_bool_val(cond))
2308         {
2309             //continue只對interp里面的執行起作用, 不會對外面有影響.
2310             interp();
2311             //cout << prog << endl;
2312 
2313         }
2314         else   // otherwise, skip to end of loop
2315         {
2316             find_eob();
2317             if(for_local)
2318             {
2319                 local_var_stack.resize(nest_scope_stack.top());
2320                 nest_scope_stack.pop();
2321             }
2322             return;
2323         }
2324         if(breakfound)
2325         {
2326             breakfound = false;
2327             if(for_local)
2328             {
2329                 local_var_stack.resize(nest_scope_stack.top());
2330                 nest_scope_stack.pop();
2331             }
2332             return;
2333         }
2334         if(continuefound)
2335         {
2336             continuefound = false;
2337         }
2338 
2339 
2340         prog = temp2; // go to increment expression
2341 
2342         // Check for break in loop.
2343 
2344 
2345 
2346         // Evaluate the increment expression.
2347         eval_exp(cond);
2348 
2349         prog = temp; // loop back to top
2350     }
2351 
2352 }
2353 
2354 // Execute a cout statement.
2355 void exec_cout()
2356 {
2357     anonymous_var val;
2358 
2359     get_token();
2360     if(*token != LS) throw InterpExc(SYNTAX);
2361     do
2362     {
2363         get_token();
2364 
2365         if(token_type == STRING)
2366         {
2367             // Output a string.
2368             cout << token;
2369         }
2370         else if(tok == ENDL)
2371         {
2372             cout << endl;
2373         }
2374         else
2375         {
2376             //cout << token << " :---" << endl;
2377             putback();
2378             eval_exp(val);
2379             //cout << val.float_value << "<<<" << endl;
2380             cout_var(val);
2381         }
2382 
2383         get_token();
2384     }
2385     while(*token == LS); //<<
2386 
2387     if(*token != ';') throw InterpExc(SEMI_EXPECTED);
2388 }
2389 
2390 // Execute a cin statement.
2391 void exec_cin()
2392 {
2393     token_ireps vtype;
2394 
2395     get_token();
2396     if(*token != RS) throw InterpExc(SYNTAX);
2397 
2398     do
2399     {
2400         get_token();
2401         if(token_type != IDENTIFIER)
2402             throw InterpExc(NOT_VAR);
2403 
2404         vtype = find_var_type(token);
2405         anonymous_var tmp;
2406         tmp.var_type = vtype;
2407 
2408         cin_var(tmp);
2409         assign_var(token, tmp);
2410         get_token();
2411     }
2412     while(*token == RS); //RS 是>>
2413 
2414     if(*token != ';') throw InterpExc(SEMI_EXPECTED);
2415 }
2416 
2417 
2418 // Find the end of a block.
2419 //#這里find_eob在邏輯上做了一點修改, 由外部保證調用的正確
2420 //如果開始的是{, 那么就處理一個block, 否則就調用find_eol處理一個;語句.
2421 void find_eob()
2422 {
2423     int brace;
2424 
2425     get_token();
2426     //cout << token <<  " find_eob" <<endl;
2427     if(*token != '{')
2428     {
2429         putback();
2430         find_eol();
2431         return ;
2432     }
2433 
2434     brace = 1;
2435 
2436     do
2437     {
2438         get_token();
2439         //cout << token <<  " find_eob" <<endl;
2440         if(*token == '{') brace++;
2441         else if(*token == '}') brace--;
2442     }
2443     while(brace && tok != END);
2444 
2445     if(tok == END) throw InterpExc(UNBAL_BRACES);
2446 }
2447 
2448 void find_eol()
2449 {
2450     do
2451     {
2452         get_token();
2453     }
2454     while (*token != ';' && tok != END);
2455 
2456     if(tok == END) throw InterpExc(SYNTAX);
2457 }
2458 
2459 // Determine if an identifier is a variable. Return
2460 // true if variable is found; false otherwise.
2461 bool is_var(char *vname)
2462 {
2463     // See if vname a local variable.
2464     if(!local_var_stack.empty())
2465         for(int i = local_var_stack.size() - 1;
2466                 i >= func_call_stack.top(); i--)
2467         {
2468             if(!strcmp(local_var_stack[i].var_name, vname))
2469                 return true;
2470         }
2471 
2472     // See if vname is a global variable.
2473     for(unsigned i = 0; i < global_vars.size(); i++)
2474         if(!strcmp(global_vars[i].var_name, vname))
2475             return true;
2476 
2477     return false;
2478 }
2479 
2480 // Return the type of variable.
2481 token_ireps find_var_type(char *vname)
2482 {
2483     // First, see if it's a local variable.
2484     if(!local_var_stack.empty())
2485         for(int i = local_var_stack.size() - 1;
2486                 i >= func_call_stack.top(); i--)
2487         {
2488             if(!strcmp(local_var_stack[i].var_name, vname))
2489                 return local_var_stack[i].value.var_type;
2490         }
2491 
2492     // Otherwise, try global vars.
2493     for(unsigned i = 0; i < global_vars.size(); i++)
2494         if(!strcmp(global_vars[i].var_name, vname))
2495             return local_var_stack[i].value.var_type;
2496 
2497     return UNDEFTOK;
2498 }
2499 
2500 
2501 /***********************************************************************
2502  libcpp.cpp, 主要是對庫函數的封裝
2503 ************************************************************************/
2504 
2505 // Add more of your own, here.
2506 
2507 #include <iostream>
2508 #include <cstdlib>
2509 #include <cstdio>
2510 #include "mccommon.h"
2511 
2512 using namespace std;
2513 
2514 // Read a character from the console.
2515 // If your compiler supplies an unbuffered
2516 // character intput function, feel free to
2517 // substitute it for the call to cin.get().
2518 anonymous_var call_getchar()
2519 {
2520     char ch;
2521 
2522     ch = getchar();
2523 
2524     // Advance past ()
2525     get_token();
2526     if(*token != '(')
2527         throw InterpExc(PAREN_EXPECTED);
2528 
2529     get_token();
2530     if(*token != ')')
2531         throw InterpExc(PAREN_EXPECTED);
2532     anonymous_var val;
2533     val.var_type = CHAR;
2534     val.int_value = ch;
2535     return val;
2536 }
2537 
2538 // Write a character to the display.
2539 anonymous_var call_putchar()
2540 {
2541     anonymous_var value;
2542 
2543     eval_exp(value);
2544 
2545     putchar(char(value.int_value));
2546 
2547     return value;
2548 }
2549 
2550 // Return absolute value.
2551 anonymous_var call_abs()
2552 {
2553     anonymous_var val;
2554 
2555     eval_exp(val);
2556     abs_var(val);
2557     return val;
2558 }
2559 
2560 // Return a randome integer.
2561 anonymous_var call_rand()
2562 {
2563 
2564     // Advance past ()
2565     get_token();
2566     if(*token != '(')
2567         throw InterpExc(PAREN_EXPECTED);
2568 
2569     get_token();
2570     if(*token != ')')
2571         throw InterpExc(PAREN_EXPECTED);
2572 
2573     anonymous_var val;
2574     val.var_type = INT;
2575     val.int_value = rand();
2576     return val;
2577 }

~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM