开发编程语言(九):print 函数的实现

随笔 2016-10-28

起步

这里的不再是用户自定义的函数,而是讲如何书写内核函数,并通过注册向用户抛出声明。以及同样涉及了参数列表,类型转换和值向上级返回。

注册

系统函数的注册,是需要在创建解释器后进行的初始化之一的步骤:

static void add_native_functions(ORG_Interpreter *inter) {
    ORG_add_native_function(inter, "print", org_nv_print_proc);
}

add_native_functions()是在解释器创建后要初始化系统函数的。惭愧我只完成了一个print的功能,ORG_add_native_function()就是向外部提供的函数,为以后写第三方拓展,插件等预设的一个注册函数的入口。

注册函数原型:void ORG_add_native_function(ORG_Interpreter *inter, char *name, ORG_NativeFunctionPro *pro),第一个参数是解释器指针,这是注入到哪个解释器,因为include file这样是可能存在多个解释器,虽然include语法没写= =。第二参数就是在用户要调用的函数名。第三个参数是具体实现的函数指针:

void ORG_add_native_function(ORG_Interpreter *inter, char *name, ORG_NativeFunctionPro *pro) {
    FunctionDefine *fd;
    fd = org_malloc(sizeof(FunctionDefine));
    fd->name = name;
    fd->type = NATIVE_FUNCTION_DEF;
    fd->u.native_f.pro = pro;
    fd->next = inter->function_list;

    inter->function_list = fd;
}

统一是创建FunctionDefine结构体的,类似于用户自己写function被语法分析为FunctionDefine一样,不同的是执行体的不同,通过fd->type判断。

print实现

实现的最后都是通过c语言的printf()。参数列表也是个问题,所以语言上要传类型argc argv表名参数数量和参数列表。从用户传过来的统一都是ORG_Value类型的了。所以print的原型:ORG_Value org_nv_print_proc(ORG_Interpreter *interpreter, int arg_count, ORG_Value *args)。输出的就要通过对他们类型进行判断,如数字4就要用到printf("%d")。是布尔类型就手动输出printf("true");空值输出printf("null");等。附上源码:

ORG_Value org_nv_print_proc(ORG_Interpreter *interpreter, int arg_count, ORG_Value *args) {
    ORG_Value value;

    value.type = ORG_NULL_VALUE;
    size_t size = 0;
    char *ready_print;

    if (arg_count < 1) {
        exit(1);
    } else if (arg_count > 1) {
        exit(1);
    }

    switch (args[0].type) {
        case ORG_BOOLEAN_VALUE:
            if (args[0].u.boolean_value) {
                printf("true");
            } else {
                printf("false");
            }
            break;
        case ORG_INT_VALUE:
            printf("%d", args[0].u.int_value);
            break;
        case ORG_DOUBLE_VALUE:
            printf("%f", args[0].u.double_value);
            break;
        case ORG_STRING_VALUE:
            printf("%s", args[0].u.string_value->string);
            break;
        case ORG_NATIVE_POINTER_VALUE:
            printf("(%s:%p)",
                   args[0].u.native_pointer.info->name,
                   args[0].u.native_pointer.pointer);
            break;
        case ORG_NULL_VALUE:
            printf("null");
            break;
    }
    return value;
}

调用

语法分析后执行都是通过eval.c中eval_function_call_expression()执行的。不管是用户函数还是系统函数:

/**
 * 调用函数时执行
 */
static ORG_Value eval_function_call_expression(ORG_Interpreter *inter, LocalEnvironment *env, Expression *expr) {
    ORG_Value value;
    FunctionDefine *func;

    char *identifier = expr->u.function_call_expression.identifier;
    func = org_search_function(identifier);
    if (func == NULL) {
        //runtime error
        exit(1);
    }

    switch (func->type) {
        case ORIGIN_FUNCTION_DEF:
            value = call_origin_function(inter, env, expr, func);
            break;
        case NATIVE_FUNCTION_DEF:
            value = call_native_function(inter, env, expr, func->u.native_f.pro);
            break;
        default:
            break;
    }

    return value;
}

通过函数名进行查找org_search_function()解释器里会有一个列表来保存函数信息,系统对外开放的函数式在解释器创建后的初始化,所以在列表的前面,以至于用户是无法覆盖系统提供的函数的。通过func->type的判断执行究竟是用户自定义的函数还是系统函数。


本文由 hongweipeng 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

赏个馒头吧