Desarrollé un pequeño lenguaje de script y recién comencé a escribir los primeros enlaces de bibliotecas nativas. Esta es prácticamente la primera vez que escribo una extensión nativa a un lenguaje de script, así que me he encontrado con un problema conceptual.
Me gustaría escribir código de pegamento para bibliotecas populares para que puedan usarse desde este lenguaje, y debido al diseño del motor que he escrito, esto se logra utilizando una matriz de C que struct
describe el nombre de la función visible por el máquina virtual, junto con un puntero de función.
Por lo tanto, un enlace nativo es realmente solo una variable de matriz global, y ahora obviamente debo darle un nombre (preferiblemente bueno). En C, es idiomático poner las propias funciones en un "espacio de nombres" anteponiendo un prefijo personalizado a los nombres de las funciones, como en myscript_parse_source()
o myscript_run_bytecode()
. El nombre personalizado idealmente describirá el nombre de la biblioteca de la que forma parte. Aquí surge la confusión.
Digamos que estoy escribiendo un enlace para libcURL
. En este caso, parece razonable llamar a mi biblioteca de extensiones curl_myscript_binding
, así:
MYSCRIPT_API const MyScriptExtFunc curl_myscript_lib[10];
Pero ahora esto choca con el curl
espacio de nombres. (Incluso he pensado en llamarlo, curlmyscript_lib
pero desafortunadamente, libcURL no usa exclusivamente el curl_
prefijo: las API públicas contienen macros como CURLCODE_*
y CURLOPT_*
, por lo que supongo que esto también saturaría el espacio de nombres).
Otra opción sería declararlo como myscript_curl_lib
, pero eso es bueno siempre que yo sea el único que escriba enlaces (ya que sé lo que estoy haciendo con mi espacio de nombres). Tan pronto como otros contribuyentes comienzan a agregar sus propios enlaces nativos, ahora saturan el myscript
espacio de nombres. (He investigado un poco, y parece que, por ejemplo, la unión Perl cURL sigue este patrón. No estoy seguro de qué debería pensar al respecto ...)
Entonces, ¿cómo sugiere que nombre mis variables? ¿Hay alguna pauta general que deba seguirse?
SomeLang_register_extension("curl", "H2CO3", "000.001.000", the_extension)
dondethe_extension
apunta a alguna estructura de extensión pero no es visible a nivel mundial. Su idioma mantendría una estructura de datos interna para clasificar las extensiones por nombre, versión y autor.Respuestas:
Bueno, de manera realista, no es necesario contener una matriz global de funciones exportadas solo para hacerlas visibles para su entorno de tiempo de ejecución.
Una buena pregunta es si su entorno de ejecución guarda el puntero de función y el nombre asociado a él.
Su noción de usar una matriz global para exportar funciones solo tiene sentido si su entorno de ejecución no guarda esa información, pero supongo que debe guardarla para que el entorno de ejecución de la VM se ejecute correctamente.
Una característica común que se agrega al lenguaje de script como el suyo es la idea de registrar sus funciones .
Esencialmente, necesita un medio para almacenar la función exportada ptr y el nombre del puntero de la función exportada que se utilizará en el código del script.
Sé de dos opciones que podrías implementar para esto:
Un mapa hash que utilizará el nombre de la función del lado del script como la clave de cadena y la función ptr como el valor asociado a esa clave.
exported_funcs["do_thing"] = &native_do_thing;
Comúnmente utilizado en lenguajes de secuencias de comandos de sistemas embebidos como Pawn, puede usar los datos de secuencia de comandos en sí para almacenar el puntero de función. Cuando "registra" la función, itera la tabla de funciones exportadas del script y busca el nombre en el que se registrará la función exportada; una vez que haya encontrado ese nombre, sobrescriba los datos de la secuencia de comandos (no el archivo de secuencia de comandos en sí, sino los datos de la memoria de secuencia de comandos cargada) y esencialmente ha almacenado el puntero de función nativo.
FuncPtrType **table_entry = get_script_entry_ptr(func_name); *table_entry = func_ptr;
Recomiendo encarecidamente que, para la segunda opción, le dé a la entrada de la tabla el tamaño suficiente para acomodar los tamaños de punteros de todas las arquitecturas, especialmente la entrada debe ser de 8 bytes.
fuente