承接上一篇日志, 我對原來的解釋器做一點小小的改動.
大致增加了如下特性:
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, 所以僅供參考.

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 }
~~