From e57e63d0d2a0e4c38460d399a0c62d140a633706 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 22 Oct 2026 14:02:47 +0000 Subject: docs: document C-struct records for EXTERN Describe which TYPE records count as C structs, passing them by value and by pointer as parameters, RETURNS and variadic arguments, and the recursive pointer types EXTERN accepts. Note the clangCodeGen dependency and the CABI sources in the architecture notes. Co-Authored-By: Claude Opus 5.5 --- doc/language/keyword/cpsc-keyword-extern.7.md | 36 ++++++++++++++++++++++++--- doc/language/keyword/cpsc-keyword-type.7.md | 4 ++- 2 files changed, 36 insertions(+), 4 deletions(-) (limited to 'doc') diff --git a/doc/language/keyword/cpsc-keyword-extern.7.md b/doc/language/keyword/cpsc-keyword-extern.7.md index 5797a4f..1de7a40 100644 --- a/doc/language/keyword/cpsc-keyword-extern.7.md +++ b/doc/language/keyword/cpsc-keyword-extern.7.md @@ -15,9 +15,11 @@ EXTERN "C" EXTERN_PROCEDURE name(type, ...) EXTERN is a compiler extension, allowed only at top level. It declares a C function without a body; there is no ENDFUNCTION or ENDPROCEDURE. The name is the exact C symbol; calls from pseudocode remain case insensitive. Call an EXTERN_FUNCTION in an expression and an EXTERN_PROCEDURE with CALL. -Parameters list only types. Parameter and result types must be C types: C_INT, C_CHAR, C_STRING, C_DOUBLE or a C_TYPE alias, including pointers. void is not allowed; use EXTERN_PROCEDURE for a C function returning void. EXTERN_FUNCTION requires RETURNS and EXTERN_PROCEDURE does not accept it. Structs, BYREF and BYVAL are unsupported; declare a C pointer parameter and pass ^Variable instead. Pseudocode values must be cast, as for other C values. +Parameters list only types. Parameter and result types must be C types (C_INT, C_CHAR, C_STRING, C_DOUBLE or a C_TYPE alias, including pointers), C struct records, or pointer types such as `TYPE PInt = ^C_INT` whose chain finally points to either. Pointers to pseudocode types such as `^INTEGER` and pointer cycles such as `TYPE P = ^P` are rejected. void is not allowed; use EXTERN_PROCEDURE for a C function returning void. EXTERN_FUNCTION requires RETURNS and EXTERN_PROCEDURE does not accept it. BYREF and BYVAL are unsupported; to let C modify a variable, declare a pointer parameter and pass ^Variable instead. Pseudocode values must be cast, as for other C values. -A final `...` makes the function variadic. Variadic arguments must also be C values; they receive C default argument promotions (float to double, narrow integers and _Bool to int or unsigned int). +A C struct record is a TYPE record, not a CLASS, whose fields all have such types; a pointer field may refer to its own record, as in a linked list. A record with any other field, such as INTEGER, REAL, CHAR, BOOLEAN, STRING, an enumeration or a CLASS, is rejected with an error naming the field, for example `EXTERN parameter 1 of puts uses record Person, which is not a C struct: field Name of Person has type STRING`. cpsc does not read C headers: declare the fields in the same order and with the same C types as the C struct. A C struct record passes by value, as a copy, or through a pointer type to the record, which lets the C function change the caller's variable; neither needs a cast. Both work for parameters, RETURNS and variadic arguments. The calling convention is that of the platform's C compiler, computed with Clang's C ABI rules. + +A final `...` makes the function variadic. Variadic arguments must also be C values, C struct records or pointers to them; `^x` passes a plain pointer when x is a C value or a C struct, like C's `&x`. C scalars receive C default argument promotions (float to double, narrow integers and _Bool to int or unsigned int). As in C, records and pointers are not promoted; the C function reads them with `va_arg(ap, struct S)` or `va_arg(ap, struct S *)`. Every EXTERN symbol must be defined by an object named with INCLUDE_OBJ, otherwise compilation fails. EXTERN cannot be combined with OVERLOAD or share a name with a FUNCTION or PROCEDURE. As in C, the same function may be declared again in the same or another input file when the signature is identical (equivalent C aliases match); conflicting declarations are errors. Each file sees its own declarations and those of the files it includes. @@ -32,6 +34,34 @@ Count <- printf((C_STRING)"%d|", abs((C_INT)-5)) OUTPUT "" ``` +`vec.c`, compiled with `cc -c vec.c`: + +```text +struct Vec2 { double x, y; }; +double vec2_dot(struct Vec2 a, struct Vec2 b) { return a.x * b.x + a.y * b.y; } +void vec2_scale(struct Vec2 *v, double k) { v->x *= k; v->y *= k; } +``` + +`me.cps`: + +```text +INCLUDE_OBJ "vec.o" +TYPE Vec2 + DECLARE X : C_DOUBLE + DECLARE Y : C_DOUBLE +ENDTYPE +TYPE Vec2Ptr = ^Vec2 +EXTERN "C" EXTERN_FUNCTION vec2_dot(Vec2, Vec2) RETURNS C_DOUBLE +EXTERN "C" EXTERN_PROCEDURE vec2_scale(Vec2Ptr, C_DOUBLE) +DECLARE V : Vec2 +V.X <- (C_DOUBLE)1.5 +V.Y <- (C_DOUBLE)2 +CALL vec2_scale(^V, (C_DOUBLE)2) +OUTPUT vec2_dot(V, V) +``` + +Run with `cpsc me.cps -r` to print `25.000000`. + # SEE ALSO -[cpsc-keyword-include_obj(7)](cpsc-keyword-include_obj.7.md), [cpsc-keyword-c_type(7)](cpsc-keyword-c_type.7.md), [cpsc-keyword-call(7)](cpsc-keyword-call.7.md), [cpsc-language-overview(7)](../cpsc-language-overview.7.md). +[cpsc-keyword-include_obj(7)](cpsc-keyword-include_obj.7.md), [cpsc-keyword-c_type(7)](cpsc-keyword-c_type.7.md), [cpsc-keyword-type(7)](cpsc-keyword-type.7.md), [cpsc-keyword-call(7)](cpsc-keyword-call.7.md), [cpsc-language-overview(7)](../cpsc-language-overview.7.md). diff --git a/doc/language/keyword/cpsc-keyword-type.7.md b/doc/language/keyword/cpsc-keyword-type.7.md index 1ca245f..c460117 100644 --- a/doc/language/keyword/cpsc-keyword-type.7.md +++ b/doc/language/keyword/cpsc-keyword-type.7.md @@ -23,6 +23,8 @@ A prefix caret takes an address (`^variable`); a suffix caret dereferences a poi Records contain one or more DECLARE fields and end with ENDTYPE. Access fields with a dot. Whole records copy by value; array fields are unsupported. Distinct user-defined type names remain distinct types. SET/DEFINE are reserved but unsupported. +A record whose fields are all C types, such records or pointer types to either is a C struct: EXTERN functions take and return it by value or through a pointer type. See [cpsc-keyword-extern(7)](cpsc-keyword-extern.7.md). + C_TYPE imports a native C type as an alias. Unlike the original enumerations, records and pointer declarations, C aliases with the same underlying C type are interchangeable. See [cpsc-keyword-c_type(7)](cpsc-keyword-c_type.7.md) for supported types and explicit casts. # EXAMPLE @@ -42,4 +44,4 @@ OUTPUT Position.X # SEE ALSO -[cpsc-language-overview(7)](../cpsc-language-overview.7.md), [cpsc-keyword-declare(7)](cpsc-keyword-declare.7.md), [cpsc-keyword-class(7)](cpsc-keyword-class.7.md), [cpsc-keyword-try(7)](cpsc-keyword-try.7.md). +[cpsc-language-overview(7)](../cpsc-language-overview.7.md), [cpsc-keyword-declare(7)](cpsc-keyword-declare.7.md), [cpsc-keyword-class(7)](cpsc-keyword-class.7.md), [cpsc-keyword-extern(7)](cpsc-keyword-extern.7.md), [cpsc-keyword-try(7)](cpsc-keyword-try.7.md). -- cgit v1.3.1-4-g156e