自己动手写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 */
- }