Форт как интерактивный тестер программ на C

Я хочу использовать интерактивный язык для тестирования некоторого кода C из устаревшего проекта. Я немного знаю Форт, но никогда не использовал его в реальном проекте. Я смотрю на pForth прямо сейчас.

Разумно ли использовать интерактивный интерпретатор Forth для проверки поведения некоторых функций в программе на C? Этот код C содержит множество структур, указателей на структуры, дескрипторов и других общих структур, встречающихся в C.

Я полагаю, мне придется написать некоторый связующий код для обработки передачи параметров и, возможно, некоторого распределения структуры на стороне Forth. Мне нужна оценка от кого-то с опытом в этой области. Стоит ли оно того?


person ivarec    schedule 01.05.2013    source источник
comment
Конечно, было бы разумнее написать наборы тестов для вашего кода C на языке, который хорошо интегрируется с C. Давайте посмотрим, я уверен, что видел один из тех, что лежат здесь. О, да, вот он - он называется C.   -  person paxdiablo    schedule 01.05.2013
comment
Я хочу что-то интерактивное, и у меня нет базовой ОС. Чтобы использовать C, мне пришлось бы написать интерпретатор Little, что кажется более проблематичным, чем использование Forth или Lua. Отсюда Вопрос.   -  person ivarec    schedule 01.05.2013
comment
pForth, похоже, поддерживает вызов функций C изнутри. Я не использовал pForth, поэтому не знаю, насколько эффективна эта функция. Будет ли это что-то, что будет развернуто в более крупной организации? Если это так, вам может понадобиться обосновать свое решение использовать pForth вместо использования C. Я сам не имею никаких предубеждений против использования Forth, если это правильный инструмент для данной ситуации. Я просто хорошо осведомлен о том, что происходит в магазине C/C++, когда я упоминаю другие языки. :)   -  person Dave Newman    schedule 01.05.2013
comment
Это просто, чтобы помочь мне протестировать и понять огромный устаревший проект. Я с тобой согласен. Я пробовал pForth с C, и это хорошо, но я хотел бы услышать от кого-нибудь с опытом, с какими проблемами я могу столкнуться.   -  person ivarec    schedule 01.05.2013
comment
Я ни в коем случае не являюсь экспертом по Forth, но я был очарован им в течение многих лет и сделал с его помощью несколько небольших утилит. Если pForth работает для вас и вам это нравится, используйте его во что бы то ни стало, но я бы, вероятно, использовал Python. Он также интерактивен и хорошо интегрируется с C.   -  person jcomeau_ictx    schedule 11.05.2013
comment
Есть варианты получше, но я хотел бы сделать это на очень ограниченном оборудовании. Нет ОС POSIX. Libffi, вероятно, не будет работать.   -  person ivarec    schedule 13.05.2013


Ответы (1)


Если вы хотите интерактивное тестирование и ориентируетесь на встраиваемые платформы, то Forth, безусловно, является хорошим кандидатом. Вы всегда найдете реализацию Forth, которая работает на вашей целевой платформе. Написать один даже не сложно, если это необходимо.

Вместо того, чтобы писать связующий код, специфичный для ваших непосредственных потребностей, используйте универсальный интерфейс Forth to C. Я использую общий C-интерфейс gforth, который очень прост в использовании. Для обработки структуры в Forth я использую реализация в стиле MPE, которая очень гибкая, когда дело доходит до взаимодействия с C (см. Однако для правильного выравнивания см. gforth %align / %allot / nalign).

Определение слов обработки структуры общего назначения занимает около 20 строк кода Forth, то же самое для обработки одиночных связанных списков или хеш-таблиц.

Поскольку вы не можете использовать gforth (только POSIX), напишите модуль расширения для выбранного вами Forth, который реализует аналогичный интерфейс C. Просто убедитесь, что ваш Forth и модуль интерфейса C используют те же функции malloc() и free(), что и код C, который вы хотите протестировать.

С таким интерфейсом вы можете делать все в Forth, просто определяя слова-заглушки (т. е. сопоставлять слова Forth с функциями и структурами C).

Вот пример тестового сеанса, в котором я вызываю gettimeofday libc, используя интерфейс C gforth.

s" structs.fs" included also structs \ load structure handling code

clear-libs
s" libc" add-lib  \ load libc.so. Not really needed for this particular library

c-library libc    \ stubs for C functions
\c #include <sys/time.h>
c-function gettimeofday gettimeofday a a -- n ( struct timeval *, struct timezone * -- int )
end-c-library

struct timeval          \ stub for struct timeval
    8 field: ->tv_sec   \ sizeof(time_t) == 8 bytes on my 64bits system
    8 field: ->tv_usec
end-struct

timeval buffer: tv

\ now call it (the 0 is for passing NULL for struct timezone *)
tv 0 gettimeofday .  \ Return value on the stack. output : 0
tv ->tv_sec @ .      \ output : 1369841953

Обратите внимание, что tv ->tv_sec фактически эквивалентен (void *)&tv + offsetof(struct timeval, tv_sec) в C, поэтому он дает вам адрес члена структуры, поэтому вам нужно получить значение с помощью @. Еще одна проблема: поскольку я использую 64-битный Форт, где размер ячейки равен 8 байтам, сохранение/выборка 8-байтового long является простым, но выборка/сохранение 4-байтового int требует специальной обработки. Во всяком случае, Форт упрощает эту задачу: просто определите для этого специальные слова int@ и int!.

Как вы можете видеть, с хорошим универсальным интерфейсом C вам не нужно писать какой-либо связующий код на C, нужны только заглушки Forth для ваших функций и структур C, но это действительно просто (и большая часть этого может быть автоматически сгенерированный из ваших заголовков C).

Когда вы будете довольны своими интерактивными тестами, вы можете перейти к автоматическим тестам:

  • Скопируйте/вставьте весь ввод/вывод из сеанса интерактивного тестирования в файл с именем testXYZ.log.
  • удалите вывод (сохранив только ввод) из журнала сеанса и запишите его в файл с именем testXYZ.fs
  • Чтобы запустить тест, передайте testXYZ.fs четвертому интерпретатору, запишите выходные данные и сравните их с testXYZ.log.

Поскольку удаление вывода из журнала интерактивного сеанса может быть несколько утомительным, вы также можете начать с написания тестового сценария testXYZ.fs, затем запустить его и записать вывод testXYZ.log, но я предпочитаю начинать с интерактивного журнала сеанса.

И вуаля !

Для справки, вот код обработки структуры, который я использовал в приведенном выше примере:

\ *****************************************************************************
\ structures handling
\ *****************************************************************************

\ Simple structure definition words. Structure instances are zero initialized.
\
\ usage :
\ struct foo
\     int: ->refCount
\     int: ->value
\ end-struct
\ struct bar
\            int: ->id
\     foo struct: ->foo
\       16 chars: ->name
\ end-struct
\
\ bar buffer: myBar
\ foo buffer: myFoo
\ 42 myBar ->id !
\ myFoo myBar ->foo !
\ myBar ->name count type
\ 1 myBar ->foo @ ->refCount +! \ accessing members of members could use a helper word

: struct ( "name" -- addr 0 ; named structure header )
    create here 0 , 0
  does>
    @ ;

\ <field-size> FIELD <field-name>
\ Given a field size on the stack, compiles a word <field-name> that adds the
\ field size to the number on the stack.

: field: ( u1 u2 "name" -- u1+u2 ; u -- u+u2 )
    over >r \ save current struct size
    : r> ?dup if
    postpone literal postpone +
    then
    postpone ;
    + \ add field size to struct size
; immediate

: end-struct ( addr u -- ; end of structure definition )
    swap ! ;

: naligned ( addr1 u -- addr2 ; aligns addr1 to alignment u )
    1- tuck + swap invert and ;

\ Typed field helpers
: int: cell naligned cell postpone field: ; immediate
: struct: >r cell naligned r> postpone field: ; immediate
: chars: >r cell naligned r> postpone field: ; immediate
\ with C style alignment
4 constant C_INT_ALIGN
8 constant C_PTR_ALIGN
4 constant C_INT_SIZE
: cint: C_INT_ALIGN naligned C_INT_SIZE postpone field: ; immediate
: cstruct: >r C_PTR_ALIGN naligned r> postpone field: ; immediate
: cchars: >r C_INT_ALIGN naligned r> postpone field: ; immediate

: buffer: ( u -- ; creates a zero-ed buffer of size u )
    create here over erase allot ;
person wldsvc    schedule 29.05.2013