Add a '$EXTERN NAME(ARGTYPES) AS RET pragma so compiled BASIC can call C functions directly, the natural follow-up to Level 1 (--emit-obj / --main-name). The pragma is an apostrophe comment, so the interpreter ignores it while the compiler registers it. Map INTEGER/SINGLE/DOUBLE/STRING to int16_t/float/double/const char* at the boundary: a string argument crosses as a temporary C copy that is freed after the call, and a string return is copied into the pool. The call name is matched case-insensitively but emitted as the C symbol with the case written in the pragma. Names are recognized before parse_var() truncates identifiers to two significant characters, so multi-character C function names work. A string return that aliases a char* argument is copied before the argument temporaries are freed, which avoids a use-after-free. Over-supplied arguments are consumed without desyncing the token stream and warn on arity mismatch. Docs: getting-started.md "Foreign Functions from BASIC". Test: tests/run_ffi_test.sh, wired into CI. 63/63 compiler, 72/72 interpreter, 68/68 compat still pass. Also refile the roadmap "Next Up" backlog as git-bug issues and prune docs/roadmap.md to point at git-bug as the source of truth for planned work. Co-authored-by: Eremey Valetov <evvaletov@users.noreply.github.com>
27 lines
821 B
C
27 lines
821 B
C
/* C functions called from extern_demo.bas via '$EXTERN pragmas. */
|
|
#include <stdint.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
|
|
int16_t Cadd(int16_t a, int16_t b) { return (int16_t)(a + b); }
|
|
double Chypot(double a, double b) { return hypot(a, b); }
|
|
int16_t Getn(void) { return 42; }
|
|
|
|
const char *Greet(const char *who)
|
|
{
|
|
static char buf[128];
|
|
snprintf(buf, sizeof buf, "Hello, %s!", who);
|
|
return buf;
|
|
}
|
|
|
|
/* Returns its own argument pointer after modifying it in place. Exercises the
|
|
* string-return path where the result aliases a C-string arg temporary — the
|
|
* codegen must copy the result before freeing that temporary. */
|
|
const char *Upcase(const char *s)
|
|
{
|
|
for (char *p = (char *)s; *p; p++)
|
|
*p = (char)toupper((unsigned char)*p);
|
|
return s;
|
|
}
|