自己動手寫basic解釋器
刺蝟@http://blog.csdn.net/littlehedgehog
注: 文章basic解釋源碼摘自梁肇新先生的《編程高手箴言》(據他所說這個代碼也是網上摘錄的),源碼解讀參考《java編程藝術》。《java編程藝術》裏面自然是java版了(可能旭哥更加適合點兒),我這裏還是解讀的C版basic解釋器代碼。
表達式已求,下面可以進入程序邏輯處理了,這裏的代碼量比較大,不過都很簡單,後面主要是以程序註釋爲主。先來看看完整版的主函數:
- main (int argc,char *argv[])
- {
- char in[80];
- int answer;
- char *p_buf;
- char *t;
- if (argc!=2) {
- printf ("usage: run <filename>/n");
- exit (1);
- }
- /* allocate memory for the program */
- if (!(p_buf=(char *)malloc(PROG_SIZE))) {
- printf ("allocation failure");
- exit (1);
- }
- /* load the program to execute */
- if (!load_program(p_buf,argv[1])) exit(1);
- if (setjmp(e_buf)) exit(1); /* initialize the long jump */
- prog = p_buf;
- scan_labels(); /* 搜索所有的標籤 */
- ftos = 0; /* 初始化棧指針 這個是爲for循環作準備的 */
- gtos = 0; /* 初始化棧指針 這個是爲gosub作準備的 */
- do {
- token_type = get_token();
- /* 如果當前是變量 */
- if (token_type==VARIABLE) {
- putback(); /* 回退prog指針到變量前 */
- assignment(); /* 賦值 */
- }
- else /* 除了變量那就是關鍵字了 可能有同學會問 呃 那個比如一個數字怎麼沒考慮 請想想一個數字怎麼會單獨出現 */
- switch (tok) {
- case PRINT:
- print();
- break;
- case GOTO:
- exec_goto();
- break;
- case IF:
- exec_if();
- break;
- case FOR:
- exec_for();
- break;
- case NEXT:
- next();
- break;
- case INPUT:
- input();
- break;
- case GOSUB:
- gosub();
- break;
- case RETURN:
- greturn();
- break;
- case END:
- exit(0);
- }
- }while (tok != FINISHED);
- }
在while循環裏,我們一行一行處理源代碼,注意是一行一行的進行,比如print a,b,c 我們會在print函數裏面循環打印a,b,c 。而不會多次調用print,這種設計很巧妙。
來先看看變量賦值函數assignment:
- /* 給變量賦值 比如 a=3
- * 注意這裏爲了簡化起見,我們的變量就設置爲26個字母
- */
- assignment()
- {
- int var,value;
- /* getthe variable name */
- get_token();
- if (!isalpha(*token)) //因爲變量我們用字母代替 所以必定是字母類型
- {
- serror(4);
- return;
- }
- var = toupper(*token)-'A'; //轉化爲大寫字母 然後減去'A' 這樣讓變量在hash表中有了座次 比如A減去A爲0 這樣A字符變量在變量hash表中第一個位置
- /* get the equals sign
- * 這裏我們取a=3 中間的等號*/
- get_token();
- if (*token!='=') //既然賦值麼 肯定有等號了
- {
- serror(3);
- return;
- }
- /* a=3 等號取走了 我們來取數值 */
- get_exp(&value);
- /* 把我們取到的變量 比如a 值爲3 存放在hash表中 */
- variables[var] = value;
- }
- /* display an error message */
- void serror(int error)
- {
- char *e[] = {
- "syntax error",
- "unbalanced parentheses",
- "no expression present",
- "equal sign expected",
- "not a variable",
- "label table full",
- "duplicate label",
- "undefined label",
- "THEN expected",
- "TO expected",
- "too many nested FOR loops",
- "NEXT without FOR",
- "too many nested GOSUB",
- "RETURN without GOSUB"
- };
- printf ("%s/n",e[error]);
- longjmp(e_buf,1); /* return to save point */
- }