2013-05-01 7 views
3

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

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

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

+0

Конечно, было бы больше смысла писать тестовые жгуты для кода C на языке, который хорошо интегрируется с C. Давайте Видите, я уверен, что видел одного из тех, кто лежал здесь. О, да, вот оно - это называется ** C. ** – paxdiablo

+3

Я хочу что-то интерактивное, и у меня нет базовой ОС. Чтобы использовать C, мне пришлось бы написать небольшую интерпретаторную оболочку, которая кажется более сложной, чем использование Forth или Lua. Отсюда вопрос. – ivarec

+0

У pForth есть поддержка для вызова функций C изнутри. Я не использовал pForth, поэтому я не знаю, насколько способна эта функция. Это что-то, что будет развернуто в более крупную организацию? Если это так, вы можете оказаться вправе обосновать свое решение использовать pForth с использованием C. У меня нет предубеждений против использования Forth, если это правильный инструмент для ситуации. Я просто хорошо знаю, что происходит в магазине C/C++, когда я упоминаю другие языки. :) –

ответ

7

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

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

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

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

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

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

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 байтов длинные просты, но выборка/хранение 4 байтов int потребует некоторой специальной обработки. Во всяком случае, Forth делает это просто: просто определите для этого специальные слова [email protected] и int!.

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

После того, как вы счастливы с вашими интерактивными тестами, вы можете переходить к автоматизированным тестам:

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

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

Et voilà!

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

\ ***************************************************************************** 
\ 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 ; 
+0

Просто фантастика! Ты мужчина – ivarec