I am developing a custom LISP interpreter. It won't support defining functions like in LISP, instead all functions are mapped to C functions. When it sees an expression like,
我正在开发一个自定义LISP解释器。它不支持像LISP那样定义函数,而是将所有函数映射到C函数。当它看到这样的表达式时,
(substr 'input '1 '1)
it knows to call internal substr
function and return the result.
它知道调用内部子str函数并返回结果。
Now I am planning to implement a message
function which supports basic formatting and writes the output to stdout
. Something like,
现在我计划实现一个消息函数,该函数支持基本的格式化并将输出写到stdout。类似的,
(message "Hello, %s" name)
%s
will be replaced with value in variable name
.
%s将被替换为变量名的值。
Current plan is to directly pass the format and arguments to functions like printf
. In that way, I can support all formats that printf
supports. But problem comes with variable number of arguments. One way to do will be something like,
当前的计划是将格式和参数直接传递给printf之类的函数。这样,我就可以支持printf支持的所有格式。但问题是有不同的参数。一种方法是,
if(argcount == 1)
/* call printf with one arg */
else if(argcount == 2)
/* call printf with two arg */
....
This works, but I am wondering is there a better way to achieve this?
这是可行的,但我想知道是否有更好的方法来实现这一点?
3 个解决方案
#1
2
I doubt there is a way to do this. The reason is that the number of parameters to your lisp function is only known at runtime, but the number of arguments to a C function must be known at compile time.
我怀疑是否有办法做到这一点。原因是lisp函数的参数数量只在运行时知道,但是C函数的参数数量必须在编译时知道。
This includes va_lists unless you want to hack at them in some kind of platform specific way.
这包括va_list,除非您想以某种特定于平台的方式攻击它们。
The best you can really do is write a function in C which is capable of looping through the arguments one at a time and doing something with them. The only way I can see around this is to not only store a function pointer for each of your internal functions, but to also store a "calling convention" which will give information about whether it takes parameters in the ordinary way or whether it finishes with the equivalent of a va_list.
你能做的最好的事情就是用C编写一个函数,它可以一次一个地循环参数,并对它们进行处理。唯一的方法我可以看到在这不仅是存储为每个内部函数的函数指针,但也存储“调用协定”,将会给信息是否需要参数以普通的方式或相当于va_list是否完成。
Functions like printf would have a wrapper, printf_wrapper, say, and you'd store a function pointer to the wrapper. This wrapper would accept the format string as an ordinary parameter, followed by a list or array of other parameters (roughly analogous to a va_list).
像printf这样的函数会有一个包装器,比如说printf_wrapper,你会存储一个指向包装器的函数指针。这个包装器将接受格式字符串作为普通参数,然后是其他参数的列表或数组(大致类似于va_list)。
You might indicate that printf_wrapper finishes with a parameter that expects a list by specifying the calling conventions for the printf_wrapper function as "va_list_type", meaning that it takes the usual fixed parameters, and that all remaining parameters must be bundled up and supplied to it as a list.
您可以通过将printf_wrapper函数的调用约定指定为“va_list_type”来指示printf_wrapper以一个期望列表的参数结束,这意味着它使用了通常的固定参数,并且所有剩余的参数必须被打包并作为一个列表提供给它。
Of course writing a printf_wrapper function which can split up and parse a format string into multiple format strings is a bit of work. Here's an example of where I did precisely this so that I could add my own custom format specifiers:
当然,编写一个printf_wrapper函数(它可以将一个格式字符串分割并将它解析为多个格式字符串)有点困难。这里有一个例子,我正是这样做的,以便我可以添加我自己的自定义格式说明:
https://github.com/wbhart/bsdnt/blob/v0.26/helper.c
https://github.com/wbhart/bsdnt/blob/v0.26/helper.c
#2
0
Have your C function take parameters somewhat like argc/argv
. That is, take a parameter specifying the number of parameters, and then a pointer to a list of pointers for each parameter.
让你的C函数使用参数,比如argc/argv。也就是说,取一个指定参数数量的参数,然后取一个指向每个参数的指针列表的指针。
#3
0
Slightly better than an if-else chain would be a switch.
比if-else链更好的是一个开关。
switch(argcount){
case 1: printf(arg[0]); break;
case 2: printf(arg[0],arg[1]); break;
//etc.
}
#1
2
I doubt there is a way to do this. The reason is that the number of parameters to your lisp function is only known at runtime, but the number of arguments to a C function must be known at compile time.
我怀疑是否有办法做到这一点。原因是lisp函数的参数数量只在运行时知道,但是C函数的参数数量必须在编译时知道。
This includes va_lists unless you want to hack at them in some kind of platform specific way.
这包括va_list,除非您想以某种特定于平台的方式攻击它们。
The best you can really do is write a function in C which is capable of looping through the arguments one at a time and doing something with them. The only way I can see around this is to not only store a function pointer for each of your internal functions, but to also store a "calling convention" which will give information about whether it takes parameters in the ordinary way or whether it finishes with the equivalent of a va_list.
你能做的最好的事情就是用C编写一个函数,它可以一次一个地循环参数,并对它们进行处理。唯一的方法我可以看到在这不仅是存储为每个内部函数的函数指针,但也存储“调用协定”,将会给信息是否需要参数以普通的方式或相当于va_list是否完成。
Functions like printf would have a wrapper, printf_wrapper, say, and you'd store a function pointer to the wrapper. This wrapper would accept the format string as an ordinary parameter, followed by a list or array of other parameters (roughly analogous to a va_list).
像printf这样的函数会有一个包装器,比如说printf_wrapper,你会存储一个指向包装器的函数指针。这个包装器将接受格式字符串作为普通参数,然后是其他参数的列表或数组(大致类似于va_list)。
You might indicate that printf_wrapper finishes with a parameter that expects a list by specifying the calling conventions for the printf_wrapper function as "va_list_type", meaning that it takes the usual fixed parameters, and that all remaining parameters must be bundled up and supplied to it as a list.
您可以通过将printf_wrapper函数的调用约定指定为“va_list_type”来指示printf_wrapper以一个期望列表的参数结束,这意味着它使用了通常的固定参数,并且所有剩余的参数必须被打包并作为一个列表提供给它。
Of course writing a printf_wrapper function which can split up and parse a format string into multiple format strings is a bit of work. Here's an example of where I did precisely this so that I could add my own custom format specifiers:
当然,编写一个printf_wrapper函数(它可以将一个格式字符串分割并将它解析为多个格式字符串)有点困难。这里有一个例子,我正是这样做的,以便我可以添加我自己的自定义格式说明:
https://github.com/wbhart/bsdnt/blob/v0.26/helper.c
https://github.com/wbhart/bsdnt/blob/v0.26/helper.c
#2
0
Have your C function take parameters somewhat like argc/argv
. That is, take a parameter specifying the number of parameters, and then a pointer to a list of pointers for each parameter.
让你的C函数使用参数,比如argc/argv。也就是说,取一个指定参数数量的参数,然后取一个指向每个参数的指针列表的指针。
#3
0
Slightly better than an if-else chain would be a switch.
比if-else链更好的是一个开关。
switch(argcount){
case 1: printf(arg[0]); break;
case 2: printf(arg[0],arg[1]); break;
//etc.
}