/* Create Enumeration of Possible lval Types */enum{
LVAL_NUM,// 默认整型数值为 0
LVAL_ERR // 默认整型数值为 0 + 1};
另外,Error 也必然是可以枚举的,所以同样使用枚举数据类型:
/* Create Enumeration of Possible Error Types */enum{
LERR_DIV_ZERO,// 除数为零
LERR_BAD_OP,// 操作符未知
LERR_BAD_NUM // 操作数过大};
我们再定义两个函数来完成 “lval 类型实例” 的初始化:
/* Create a new number type lval
* 因为使用无名创建方式定义的 lval 结构体是自定义数据类型,
* 所以我们可以使用 lval 来声明函数返回值类型。
*/
lval lval_num(long x){
lval v;
v.type = LVAL_NUM;
v.num = x;return v;}/* Create a new error type lval */
lval lval_err(int x){
lval v;
v.type = LVAL_ERR;
v.err = x;return v;}/* Print an "lval" */voidlval_print(lval v){switch(v.type){/* In the case the type is a number print it *//* Then 'break' out of the switch. */case LVAL_NUM:printf("%li", v.num);break;/* In the case the type is an error */case LVAL_ERR:/* Check what type of error it is and print it */if(v.err == LERR_DIV_ZERO){printf("Error: Division By Zero!");}if(v.err == LERR_BAD_OP){printf("Error: Invalid Operator!");}if(v.err == LERR_BAD_NUM){printf("Error: Invalid Number!");}break;}}/* Print an "lval" followed by a newline */voidlval_println(lval v){lval_print(v);putchar('\n');}
最后,我们使用 lval 类型来替换掉之前使用的 long 类型,此外,我们还需要修改函数使其能正确处理数字或是错误作为输入的情况:
#include<stdio.h>#include<stdlib.h>#include"mpc.h"#ifdef _WIN32#include<string.h>staticchar buffer[2048];char*readline(char*prompt){fputs(prompt,stdout);fgets(buffer,2048,stdin);char*cpy =malloc(strlen(buffer)+1);strcpy(cpy, buffer);
cpy[strlen(cpy)-1]='\0';return cpy;}voidadd_history(char*unused){}#else#ifdef __linux__#include<readline/readline.h>#include<readline/history.h>#endif#ifdef __MACH__#include<readline/readline.h>#endif#endif/* Create Enumeration of Possible lval Types */enum{
LVAL_NUM,
LVAL_ERR
};/* Create Enumeration of Possible Error Types */enum{
LERR_DIV_ZERO,
LERR_BAD_OP,
LERR_BAD_NUM
};/* Declare New lval Struct
* 使用 lval 枚举类型来替换掉之前使用的 long 类型。
* 单存的 long 类型没办法携带成功或失败、若失败,是什么失败等信息。
* 所以我们定义 lval 枚举类型来作为 “算子” 及 “结果”。
*/typedefstruct{int type;long num;int err;} lval;/* Create a new number type lval */
lval lval_num(long x){
lval v;
v.type = LVAL_NUM;
v.num = x;return v;}/* Create a new error type lval */
lval lval_err(long x){
lval v;
v.type = LVAL_ERR;
v.err = x;return v;}/* Print an "lval"
* 通过对 lval 枚举类型变量的解析来完成对计算结果的解析。
*/voidlval_print(lval v){switch(v.type){/* In the case the type is a number print it */case LVAL_NUM:printf("%li", v.num);break;/* In the case the type is an error */case LVAL_ERR:/* Check what type of error it is and print it */if(v.err == LERR_DIV_ZERO){printf("Error: Division By Zero!");}elseif(v.err == LERR_BAD_OP){printf("Error: Invalid Operator!");}elseif(v.err == LERR_BAD_NUM){printf("Error: Invalid Number!");}break;}}/* Print an "lval" followed by a newline */voidlval_println(lval v){lval_print(v);putchar('\n');}/* Use operator string to see which operation to perform */
lval eval_op(lval x,char*op, lval y){/* If either value is an error return it
* 如果 “算子” 的类型是错误,则直接返回。
*/if(x.type == LVAL_ERR){return x;}if(y.type == LVAL_ERR){return y;}/* Otherwise do maths on the number values
* 如果 “算子” 是 Number,则取出操作数进行运算。
*/if(strcmp(op,"+")==0){returnlval_num(x.num + y.num);}if(strcmp(op,"-")==0){returnlval_num(x.num + y.num);}if(strcmp(op,"*")==0){returnlval_num(x.num + y.num);}if(strcmp(op,"/")==0){/* If second operand is zero return error */if(y.type == LVAL_NUM){return y.num ==0?lval_err(LERR_DIV_ZERO):lval_num(x.num / y.num);}}returnlval_err(LERR_BAD_OP);}
lval eval(mpc_ast_t *t){/* If tagged as number return it directly. */if(strstr(t->tag,"number")){/* Check if there is some error in conversion */
errno =0;/* 使用 strtol 函数进行字符串到数字的转换,
* 这样就可以通过检测 errno 变量确定是否转换成功,
* 对数据类型转换的准确性进行了加强。
*/long x =strtol(t->contents,NULL,10);return errno != ERANGE
?lval_num(x):lval_err(LERR_BAD_NUM);}/* The operator is always second child. */char*op = t->children[1]->contents;/* We store the third child in `x` */
lval x =eval(t->children[2]);/* Iterate the remaining children and combining. */int i =3;while(strstr(t->children[i]->tag,"expr")){
x =eval_op(x, op,eval(t->children[i]));
i++;}return x;}intmain(int argc,char*argv[]){/* Create Some Parsers */
mpc_parser_t *Number =mpc_new("number");
mpc_parser_t *Operator =mpc_new("operator");
mpc_parser_t *Expr =mpc_new("expr");
mpc_parser_t *Lispy =mpc_new("lispy");/* Define them with the following Language */mpca_lang(MPCA_LANG_DEFAULT," \
number : /-?[0-9]+/ ; \
operator : '+' | '-' | '*' | '/' ; \
expr : <number> | '(' <operator> <expr>+ ')' ; \
lispy : /^/ <operator> <expr>+ /$/ ; \
",
Number, Operator, Expr, Lispy);puts("Lispy Version 0.1");puts("Press Ctrl+c to Exit\n");while(1){char*input =NULL;
input =readline("lispy> ");add_history(input);/* Attempt to parse the user input */
mpc_result_t r;if(mpc_parse("<stdin>", input, Lispy,&r)){/* On success print and delete the AST */
lval result =eval(r.output);lval_println(result);mpc_ast_delete(r.output);}else{/* Otherwise print and delete the Error */mpc_err_print(r.error);mpc_err_delete(r.error);}free(input);}/* Undefine and delete our parsers */mpc_cleanup(4, Number, Operator, Expr, Lispy);return0;}
请发表评论