Отображение переменной LISP-функции аргумента в функцию C - C - PullRequest
4 голосов
/ 30 декабря 2010

Я занимаюсь разработкой пользовательского интерпретатора LISP.Он не будет поддерживать определение функций, как в LISP, вместо этого все функции отображаются на функции C.Когда он видит выражение типа

(substr 'input '1 '1)

, он знает, как вызвать внутреннюю функцию substr и вернуть результат.

Теперь я планирую реализовать функцию message, которая поддерживает базовое форматирование и записывает вывод в stdout.Что-то вроде

(message "Hello, %s" name)

%s будет заменено значением в переменной name.

Текущий план заключается в прямой передаче формата и аргументов таким функциям, как printf.Таким образом, я могу поддерживать все форматы, которые поддерживает printf.Но проблема связана с переменным количеством аргументов.Один из способов сделать это будет что-то вроде

if(argcount == 1)
   /* call printf with one arg */
else if(argcount == 2)
   /* call printf with two arg */
....

Это работает, но мне интересно, есть ли лучший способ добиться этого?

Ответы [ 3 ]

2 голосов
/ 05 января 2011

Я сомневаюсь, что есть способ сделать это.Причина в том, что количество параметров вашей функции lisp известно только во время выполнения, но количество аргументов функции C должно быть известно во время компиляции.

Сюда входят списки va_lists, если вы не хотите взламывать их каким-либо образом для конкретной платформы.

Лучшее, что вы действительно можете сделать, это написать функцию на C, которая способна циклически перебирать аргументы по одному и что-то делать с ними.Единственный способ обойти это - не только сохранить указатель на функцию для каждой из ваших внутренних функций, но и сохранить «соглашение о вызовах», которое даст информацию о том, принимает ли он параметры обычным способом или заканчивается ли он наэквивалент va_list.

Такие функции, как printf, будут иметь оболочку, скажем, printf_wrapper, и вы сохраните указатель функции на оболочку.Эта оболочка будет принимать строку формата в качестве обычного параметра, за которым следует список или массив других параметров (примерно аналогично va_list).

Вы можете указать, что printf_wrapper заканчивается параметром, который ожидает список, указав соглашения о вызовах для функции printf_wrapper как "va_list_type", что означает, что он принимает обычные фиксированные параметры, и что все остальные параметры должны быть связаныи передается в виде списка.

Конечно, написание функции printf_wrapper, которая может разбивать и анализировать строку формата на несколько строк формата, - это немного трудоемко.Вот пример, где я сделал именно это, чтобы я мог добавить свои собственные спецификаторы формата:

https://github.com/wbhart/bsdnt/blob/v0.26/helper.c

0 голосов
/ 03 декабря 2014

Чуть лучше, чем цепочка if-else .

switch(argcount){
    case 1: printf(arg[0]); break;
    case 2: printf(arg[0],arg[1]); break;
    //etc.
}
0 голосов
/ 30 декабря 2010

Ваша функция C принимает параметры, подобные argc/argv.То есть взять параметр, указывающий количество параметров, а затем указатель на список указателей для каждого параметра.

...