Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 11:34 07 Jan 2026 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : MMbasic RP2350 V6.01.00EXP with user-defined structures

     Page 6 of 7    
Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10808
Posted: 06:57pm 01 Jan 2026
Copy link to clipboard 
Print this post

V6.01.00EXP6

MMBasic_Structures_Manual.pdf

PicoMiteV6.01.00EXP6.zip

Huge changes:
Fixes bug in passing an element of an structure array to a function - see test below

Many Math and most drawing commands are now structure enabled - see manual. Attempting to pass a structure array to a non enabled command will now give a sensible error.

Change to FIND function and SORT, EXTRACT, and INSERT commands. These now take the structure and element as a single parameter
was:
structure,element
now:
structure.element
e.g.
STRUCT SORT mystruct().name$

' StructParamTest.bas - Test passing structure array elements to subroutines
' Tests fix for: "Array dimensions" error when passing struct array element to sub
'
' Bug scenario:
'   Dim people(2) As TPerson
'   TPerson.Print people(1)  ' <- This caused "Array dimensions" error inside sub
'
' The fix ensures that when passing a single array element (like people(1)),
' the parameter is treated as a single struct, not as an array.

Option Base 1
Option Explicit

Type TPerson
 phone As integer
 surname As string Length 8
 name As string Length 7
 padding As string Length 2
End Type

Dim people(2) As TPerson = (1234,"Mather","Peter","", 5678,"Graham","Geoff","")
Dim pt As TPerson
Dim test_pass As INTEGER = 0
Dim test_fail As INTEGER = 0

Print "================================================"
Print "Structure Array Element Parameter Test Suite"
Print "================================================"
Print

' TEST 1: Pass single struct variable to sub
Print "TEST 1: Pass single struct to sub"
pt = people(1)
TPerson.Print pt
Print "  (If no error, PASS)"
test_pass = test_pass + 1
Print

' TEST 2: Pass array element to sub (THE BUG FIX TEST)
Print "TEST 2: Pass array element people(1) to sub"
TPerson.Print people(1)
Print "  (If no 'Array dimensions' error, PASS)"
test_pass = test_pass + 1
Print

' TEST 3: Pass second array element
Print "TEST 3: Pass array element people(2) to sub"
TPerson.Print people(2)
Print "  PASS"
test_pass = test_pass + 1
Print

' TEST 4: Modify through sub parameter
Print "TEST 4: Modify struct through sub parameter"
Dim before_phone%
before_phone% = people(1).phone
TPerson.Modify people(1), 9999
If people(1).phone = 9999 Then
 Print "  PASS: phone changed from "; before_phone%; " to "; people(1).phone
 test_pass = test_pass + 1
Else
 Print "  FAIL: phone still "; people(1).phone
 test_fail = test_fail + 1
EndIf
people(1).phone = before_phone%  ' Restore
Print

' TEST 5: Pass whole array to sub expecting array
Print "TEST 5: Pass whole array people() to sub"
TPerson.PrintAll people()
Print "  PASS"
test_pass = test_pass + 1
Print

' TEST 6: Copy inside sub (was working but verify)
Print "TEST 6: Copy struct inside sub"
TPerson.CopyTest people(1)
Print "  PASS"
test_pass = test_pass + 1
Print

' TEST 7: Local struct assigned from parameter
Print "TEST 7: Local struct assigned from parameter"
TPerson.LocalCopy people(2)
Print "  PASS"
test_pass = test_pass + 1
Print

Print "================================================"
Print "TEST SUMMARY"
Print "================================================"
Print "Passed: "; test_pass
Print "Failed: "; test_fail
Print
If test_fail = 0 Then
 Print "*** ALL TESTS PASSED ***"
Else
 Print "*** SOME TESTS FAILED ***"
EndIf
End

' Sub that expects a single struct (not an array)
Sub TPerson.Print(me As TPerson)
 Print "  In TPerson.Print - me.name: "; me.name
 Struct Print me
 Local p As TPerson
 p = me
 Struct Print p
End Sub

' Sub that modifies a struct parameter
Sub TPerson.Modify(me As TPerson, newPhone%)
 me.phone = newPhone%
End Sub

' Sub that expects an array of structs
Sub TPerson.PrintAll(arr() As TPerson)
 Local i%
 Print "  Printing all "; Bound(arr()); " elements:"
 For i% = 1 To Bound(arr())
   Print "    ["; i%; "] "; arr(i%).name; " "; arr(i%).surname
 Next i%
End Sub

' Sub that does STRUCT PRINT on parameter
Sub TPerson.CopyTest(me As TPerson)
 Print "  Testing STRUCT PRINT me inside sub:"
 Struct Print me
End Sub

' Sub that assigns parameter to local
Sub TPerson.LocalCopy(me As TPerson)
 Local localCopy As TPerson
 localCopy = me
 Print "  Copied to local: "; localCopy.name; " "; localCopy.surname
 Struct Print localCopy
End Sub
 
JanVolk
Senior Member

Joined: 28/01/2023
Location: Netherlands
Posts: 281
Posted: 07:57pm 01 Jan 2026
Copy link to clipboard 
Print this post

With all versions V6.01.00 RP2040 and RP2350, minifm_RC2.bas works correctly, but with all subsequent versions up to V6.01.00EXP5, it no longer works.
Has anyone else noticed this?
The options list doesn't show any additional settings, and only minifm_RC2.bas is in memory.

42946 minifm_RC2.bas

[1176] FList$(RQt)=".."
Error: String too long

Happy New Year and a healthy and enjoyable hobby year to all.

Kind regards,

Jan.
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6425
Posted: 08:27pm 01 Jan 2026
Copy link to clipboard 
Print this post

EXP6
RP2040
Tried to create a STATIC variable
 
FUNCTION thisreading(p AS INTEGER) AS room
 ' p = pin number for DHT22
 LOCAL FLOAT tmpr, hmid
 STATIC n
 IF demo_mode THEN
   IF n = 0 THEN RESTORE dummydata
   n = (n+1) MOD 144
   READ  tmpr ,hmid
 ELSE
   DEVICE HUMID p, tmpr ,hmid
 ENDIF
 thisreading.t = tmpr
 thisreading.h = hmid
END FUNCTION


Gives error:
[23] Static n
Error : Unknown structure member

Using a global variable instead works OK.

Jim
VK7JH
MMedit
 
bfwolf
Senior Member

Joined: 03/01/2025
Location: Germany
Posts: 129
Posted: 08:56pm 01 Jan 2026
Copy link to clipboard 
Print this post

  matherp said  V6.01.00EXP6

MMBasic_Structures_Manual.pdf

PicoMiteV6.01.00EXP6.zip

Huge changes:
Fixes bug in passing an element of an structure array to a function - see test below

Many Math and most drawing commands are now structure enabled - see manual. Attempting to pass a structure array to a non enabled command will now give a sensible error.

Change to FIND function and SORT, EXTRACT, and INSERT commands. These now take the structure and element as a single parameter
was:
structure,element
now:
structure.element
e.g.
STRUCT SORT mystruct().name$


Wow !!!   "The child is growing up.."    

Thanks!

  matherp said  
' StructParamTest.bas - Test passing structure array elements to subroutines
' Tests fix for: "Array dimensions" error when passing struct array element to sub
'
' Bug scenario:
'   Dim people(2) As TPerson
'   TPerson.Print people(1)  ' <- This caused "Array dimensions" error inside sub
'
' The fix ensures that when passing a single array element (like people(1)),
' the parameter is treated as a single struct, not as an array.

...



Sorry again for my "quick and dirty" test program..
But it seems to have become clear in the end, and it was helpful after all?

---

Monty Python: "And now to something completely different.."

I'm a bit hesitant to ask...  But I have another idea...
New additional Struct-Subfunction..

typeName$ = Struct(TYPEOF typeVarInstance$)

Edit: or perhaps better..
typeName$ = Struct(TYPEOF typeVarInstance)


Something "evil" with it comes to my mind...

A little hint: It would have something to do with
'EXECUTE command$' or 'CALL(userfunname$,[userfunparameters,..])'  

And with the subnames in my previous test program, which all started with a 'typeName.' - Do you already have an idea what I'm thinking about?

..But of course, bugfixing has priority..
Edited 2026-01-02 07:16 by bfwolf
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 5585
Posted: 09:26pm 01 Jan 2026
Copy link to clipboard 
Print this post

  JanVolk said  With all versions V6.01.00 RP2040 and RP2350, minifm_RC2.bas works correctly, but with all subsequent versions up to V6.01.00EXP5, it no longer works.
Has anyone else noticed this?
The options list doesn't show any additional settings, and only minifm_RC2.bas is in memory.

42946 minifm_RC2.bas

[1176] FList$(RQt)=".."
Error: String too long

Happy New Year and a healthy and enjoyable hobby year to all.

Kind regards,

Jan.


Confirm that the problem still exists in EXP6 for RP2040 nonVGA nonUSB.

Volhout
PicomiteVGA PETSCII ROBOTS
 
karlelch

Guru

Joined: 30/10/2014
Location: Germany
Posts: 310
Posted: 10:01pm 01 Jan 2026
Copy link to clipboard 
Print this post

  TassyJim said  EXP6
RP2040
Tried to create a STATIC variable
 
FUNCTION thisreading(p AS INTEGER) AS room
 ' p = pin number for DHT22
 LOCAL FLOAT tmpr, hmid
 STATIC n
 IF demo_mode THEN
   IF n = 0 THEN RESTORE dummydata
   n = (n+1) MOD 144
   READ  tmpr ,hmid
 ELSE
   DEVICE HUMID p, tmpr ,hmid
 ENDIF
 thisreading.t = tmpr
 thisreading.h = hmid
END FUNCTION


Gives error:
[23] Static n
Error : Unknown structure member

Using a global variable instead works OK.

Jim

Static Integer n?
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6425
Posted: 10:13pm 01 Jan 2026
Copy link to clipboard 
Print this post

The issue with minifm.bas can be reduced to passing an array to a sub.
'
OPTION EXPLICIT
OPTION DEFAULT INTEGER
OPTION BASE 0

DIM flist$(100) LENGTH 63

getflist "b:","aaa",flist$(),1
END
'============================
SUB GetFList(Disk$,Folder$,FList$(),SIDE)
LOCAL INTEGER RQt,DQt,FQt,i,FS
'Drive Disk$: Chdir Folder$
FList$(RQt)=".."
'TMP$=Dir$("*",DIR)
END SUB


RUN
[14] FList$(RQt)=".."
Error : String too long

Jim
Edited 2026-01-02 08:14 by TassyJim
VK7JH
MMedit
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10808
Posted: 10:35pm 01 Jan 2026
Copy link to clipboard 
Print this post

Please give me a complete test program demonstrating the STATIC bug. Is it just a poor error message? I've fixed the ".." bug. Will be in the next version
Edited 2026-01-02 08:47 by matherp
 
bfwolf
Senior Member

Joined: 03/01/2025
Location: Germany
Posts: 129
Posted: 10:46pm 01 Jan 2026
Copy link to clipboard 
Print this post

I think karlelch wrote the solution above:
https://www.thebackshed.com/forum/ViewTopic.php?TID=18519&P=6#248994

It should be perhaps be 'STATIC integer|float|string varName'
Or should 'STATIC varName' be allowed?
Pehaps rather 'STATIC n%' or 'STATIC n!' or 'STATIC s$' ?
..don't know..

Edit: Just read about the syntax for DIM which should be the same..
If I understood right, 'STATIC varName' might be allowed? Type would then be the default-type.. Perhaps it depends on 'OPTION EXPLICIT" if a type must be given?
Edited 2026-01-02 08:53 by bfwolf

Footnote added 2026-01-02 08:55 by bfwolf
@Peter: You were faster than me..
 
aFox
Senior Member

Joined: 28/02/2023
Location: Germany
Posts: 109
Posted: 10:51pm 01 Jan 2026
Copy link to clipboard 
Print this post

Hi

JSON files are a readable posibility to im- and export structure variables.

Gregor
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6425
Posted: 11:30pm 01 Jan 2026
Copy link to clipboard 
Print this post

Static bug:
 OPTION EXPLICIT
 OPTION DEFAULT INTEGER
 OPTION BASE 0
 
TYPE room
 t AS FLOAT
 h AS FLOAT
END TYPE
 
 DIM readings(144) AS room
 'dim n
 readings(144)=thisreading()
 struct PRINT readings(144)
 
FUNCTION thisreading() AS room
 LOCAL FLOAT tmpr, hmid
 STATIC n
 
 thisreading.t = 20 'tmpr
 thisreading.h = 40 'hmid
END FUNCTION



[17] Static n
Error : Unknown structure member

Jim
VK7JH
MMedit
 
LeoNicolas

Guru

Joined: 07/10/2020
Location: Canada
Posts: 555
Posted: 12:44am 02 Jan 2026
Copy link to clipboard 
Print this post

  Volhout said  
  karlelch said  
  Volhout said  In your typical case Leo, I wonder why you haven't defined constants, for use in the arrays. Makes life a lot easier.

Constants for this purpose eat up valuable variable slots.


Just learning, so I am curious if they don't require space when in structures ???
Somewhere the structure is defined, so somewhere the memory is reserved for the structure definition. Maybe that is more compact ?

Volhout


It not only uses more memory and more variable slots, having more indirections reduce the overall game performance.
 
karlelch

Guru

Joined: 30/10/2014
Location: Germany
Posts: 310
Posted: 07:30am 02 Jan 2026
Copy link to clipboard 
Print this post

I did not find anything explicit about this in the manual, but it would be great if one could pass a structure member individually to a sub (see example below). Or should one also better use extract before?

Option Base 0
Option explicit
Option Default Integer

Type TTest
 a As Integer
 b As Integer
End Type

Sub MyTest p
 Print p
End Sub

Dim test As TTest
test.a = 123

MyTest test.a
End

Causes:
Error : Incompatible type: test.a
 
karlelch

Guru

Joined: 30/10/2014
Location: Germany
Posts: 310
Posted: 08:01am 02 Jan 2026
Copy link to clipboard 
Print this post

In the MMBasic Structures User Manual, shouldn't it be "Using with PEEK(VARADDR ...) to access memory" instead of "Using with PEEK(VARTBL to access memory"?
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 5585
Posted: 08:19am 02 Jan 2026
Copy link to clipboard 
Print this post

  LeoNicolas said  
  Volhout said  
  karlelch said  
  Volhout said  In your typical case Leo, I wonder why you haven't defined constants, for use in the arrays. Makes life a lot easier.

Constants for this purpose eat up valuable variable slots.


Just learning, so I am curious if they don't require space when in structures ???
Somewhere the structure is defined, so somewhere the memory is reserved for the structure definition. Maybe that is more compact ?

Volhout


It not only uses more memory and more variable slots, having more indirections reduce the overall game performance.


As soon as I find the time I plan to test just that. I would love to be convinced otherways, but at the moment I guess structures are just a conversion layer to underlying same memory map, and mechanism, that became possible with the introduction of REDIM in 6.01.00rc. So better readability of code, more familiar for people used to other languages. But under the hood, the same.

Volhout
Edited 2026-01-02 18:26 by Volhout
PicomiteVGA PETSCII ROBOTS
 
ville56
Guru

Joined: 08/06/2022
Location: Austria
Posts: 370
Posted: 08:57am 02 Jan 2026
Copy link to clipboard 
Print this post

I think

-------------------------
Option explicit

Sub MyTest p (and no datatype)
-------------------------

doesn't go together ....

and yes, errormessages are not always to the point, but wuth a little reading the own code, I always succeeded  . If the interprter throws an error, usually there IS a reason for it.

Forgot to mention that

option explicit and option default in the same program to me is a contradiction and option explicit wins....
Edited 2026-01-02 19:00 by ville56
                                                                 
73 de OE1HGA, Gerald
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2913
Posted: 09:53am 02 Jan 2026
Copy link to clipboard 
Print this post

OPTION EXPLICIT only requires variables to be declared. It doesn't require the type to be specified so OPTION DEFAULT is still relevant if you don't want FLOAT to be the default.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10808
Posted: 09:56am 02 Jan 2026
Copy link to clipboard 
Print this post

I've fixed all reported bugs in structure interaction with subroutines including the issue raised by karlech which was a bug. I'm just starting some more comprehensive testing. In the meantime here is a technical description about how structures are implemented which may answer some of the questions raised (e.g. variable usage)
  Quote  # MMBasic Structure Implementation Technical Notes

## Overview

MMBasic structures (user-defined types) are implemented using a **single vartbl entry per structure variable**, regardless of how many members the structure contains. Structure members do NOT create individual entries in `g_vartbl`. Instead, member metadata is stored in a separate **structure type definition table** (`g_structtbl`), and member access is resolved at runtime by calculating byte offsets into a contiguous memory block.

## Architecture

### Data Structures

#### 1. Structure Type Definition (`s_structdef`)

Defined in [MMBasic.h](MMBasic.h#L288-L294):

```c
typedef struct s_structdef {
   unsigned char name[MAXVARLEN];              // Structure type name (e.g., "POINT")
   int num_members;                            // Number of members in this type
   struct s_structmember members[MAX_STRUCT_MEMBERS];  // Member definitions
   int total_size;                             // Total size in bytes (with alignment)
} structdef_val;
```

#### 2. Structure Member Definition (`s_structmember`)

Defined in [MMBasic.h](MMBasic.h#L280-L286):

```c
typedef struct s_structmember {
   unsigned char name[MAXVARLEN];  // Member name (e.g., "X", "Y")
   unsigned char type;             // T_NBR, T_STR, T_INT, or T_STRUCT (nested)
   unsigned char size;             // String max length, or nested struct type index
   int offset;                     // Byte offset within structure
   short dims[MAXDIM];             // Array dimensions (0 = not an array)
} structmember_val;
```

#### 3. Variable Table Entry (`s_vartbl`)

Structure variables use the standard variable table entry:

```c
typedef struct s_vartbl {
   unsigned char name[MAXVARLEN];  // Variable name (e.g., "PT", "POINTS")
   unsigned char type;             // T_STRUCT | T_IMPLIED (and possibly T_PTR)
   unsigned char level;            // Scope level (0 = global, >0 = local)
   unsigned char size;             // ** STRUCT TYPE INDEX ** (not string size)
   unsigned char namelen;          // Flags (NAMELEN_EXPLICIT, NAMELEN_STATIC)
   int/short dims[MAXDIM];         // Array dimensions (for struct arrays)
   union u_val {
       MMFLOAT f;
       long long int i;
       MMFLOAT *fa;
       long long int *ia;
       unsigned char *s;           // ** POINTER TO STRUCT DATA BLOCK **
   } val;
} vartbl_val;
```

### Global Tables

| Table | Purpose | Size |
|-------|---------|------|
| `g_structtbl[MAX_STRUCT_TYPES]` | Array of pointers to structure type definitions | 32 pointers |
| `g_structcnt` | Count of defined structure types | int |
| `g_vartbl[]` | Variable table (structures use ONE entry each) | MAXVARS entries |

Configuration constants from [configuration.h](configuration.h#L297-L299):
- `MAX_STRUCT_TYPES` = 32 (maximum distinct TYPE definitions)
- `MAX_STRUCT_MEMBERS` = 16 (maximum members per structure)
- `MAX_STRUCT_NEST_DEPTH` = 8 (maximum nesting depth)

## Memory Layout

### Single Structure Variable

For a structure definition:
```basic
TYPE point
   x AS FLOAT
   y AS FLOAT
END TYPE

DIM pt AS point
```

Creates:
1. **One entry in `g_structtbl`** (type definition, allocated once)
2. **One entry in `g_vartbl`** for variable `pt`
3. **One contiguous memory block** (16 bytes) pointed to by `g_vartbl[idx].val.s`

Memory layout for `pt`:
```
Offset  Content         Size
0       x (FLOAT)       8 bytes
8       y (FLOAT)       8 bytes
---     Total           16 bytes
```

### Structure Array

```basic
DIM points(100) AS point
```

Creates:
1. **One entry in `g_vartbl`** for array `points`
2. **One contiguous memory block** (16 × 101 = 1616 bytes, accounting for OPTION BASE)

Memory layout for `points(0)` through `points(100)`:
```
Offset    Content
0         points(0).x, points(0).y     (16 bytes)
16        points(1).x, points(1).y     (16 bytes)
32        points(2).x, points(2).y     (16 bytes)
...
1600      points(100).x, points(100).y (16 bytes)
```

## How vartbl Fields Are Used for Structures

| Field | Usage for Structures |
|-------|---------------------|
| `name[]` | Variable name (e.g., "PT", "POINTS") |
| `type` | `T_STRUCT \| T_IMPLIED` (may include `T_PTR` for STATIC) |
| `level` | Scope level (0 = global) |
| `size` | **Structure type index** into `g_structtbl[]` |
| `namelen` | Flags: `NAMELEN_STATIC` for static variables |
| `dims[]` | Array dimensions (0 for simple struct, >0 for arrays) |
| `val.s` | **Pointer to allocated struct data** |

### Key Insight: `size` Field Repurposing

For regular variables, `size` holds string length. For structures:
- `size` holds the **index into `g_structtbl`** that defines this struct's type
- Retrieved via: `int struct_type = (int)g_vartbl[idx].size;`
- Then access type definition: `g_structtbl[struct_type]`

## Structure Member Access Resolution

When code accesses `pt.x` or `points(5).y`:

### Step 1: Parse Variable Name
In `findvar()` ([MMBasic.c](MMBasic.c#L3378-L3420)):
- Detect dot in name: `unsigned char *dot = strchr(name, '.')`
- Split into base name ("pt") and member path ("x")

### Step 2: Find Base Variable
Using `FindStructBase()` ([MMBasic.c](MMBasic.c#L3202-L3260)):
- Hash-based lookup in local then global variable space
- Verify `type & T_STRUCT`
- Return struct type index from `size` field

### Step 3: Resolve Member Path
Using `ResolveStructMember()` ([MMBasic.c](MMBasic.c#L2944-L3195)):
- Look up member in `g_structtbl[type_idx]->members[]`
- Use `FindStructMember()` for name matching
- Calculate byte offset from `member.offset`
- Handle nested structs recursively
- Handle array indexing for member arrays

### Step 4: Return Pointer
- Final pointer = `base_ptr + total_offset + array_offset`
- Set `g_StructMemberType` for type checking
- Set `g_StructMemberOffset` and `g_StructMemberSize` for STRUCT operations

## Structure Definition Processing

Structure types are parsed during `PrepareProgram()` (program preparation phase), not at runtime.

### Parsing Flow ([MMBasic.c](MMBasic.c#L650-L810))

1. **Detect TYPE token** in token stream
2. **Parse type name** and check for duplicates
3. **Allocate `s_structdef`** in memory
4. **Parse members** until END TYPE:
  - Call `ParseStructMember()` ([Commands.c](Commands.c#L5891-L6070))
  - Calculate aligned offsets
  - Support INTEGER, FLOAT, STRING LENGTH n, nested types
5. **Finalize type** with padding for alignment
6. **Increment `g_structcnt`**

### Member Offset Calculation

From [Commands.c](Commands.c#L6024-L6032):
```c
// Align integers, floats, and nested structures to 8-byte boundary
offset = sd->total_size;
if ((type == T_INT || type == T_NBR || type == T_STRUCT) && (offset % 8) != 0) {
   offset = ((offset / 8) + 1) * 8;
}
```

## Variable Creation (DIM AS structtype)

When `DIM pt AS point` executes ([Commands.c](Commands.c#L4660-L4890)):

1. **Detect AS keyword** and structure type name
2. **Look up type** in `g_structtbl` → get type index
3. **Call `findvar()`** with `V_DIM_VAR`
4. **Allocate memory** for struct data (size from `g_structtbl[idx]->total_size`)
5. **Set vartbl fields**:
  - `type = T_STRUCT | T_IMPLIED`
  - `size = struct_type_index`
  - `val.s = allocated_memory_pointer`

### For Arrays
Memory allocated = `total_size × num_elements`

Where `num_elements` = product of (dim[i] + 1 - OPTION BASE) for all dimensions.

## STATIC Structure Variables

STATIC structures create TWO vartbl entries:

1. **Global entry** with mangled name (`"funcname\x1evarname"`)
  - Holds actual struct data
  - Persists across function calls

2. **Local entry** with original name
  - `type |= T_PTR` (pointer flag)
  - `val.s` points to global entry's data
  - Destroyed when function exits

The `\x1e` (ASCII Record Separator) in the name prevents conflicts with structure member syntax (which uses `.`).

## Example: Complete Memory Trace

```basic
TYPE room
   temp AS FLOAT
   name AS STRING LENGTH 20
END TYPE

FUNCTION thisreading() AS room
   STATIC integer n  ' Creates global "thisreading\x1en"
   STATIC data AS room  ' Creates global "thisreading\x1edata"
   n = n + 1
   data.temp = 22.5
   data.name = "Kitchen"
   thisreading = data
END FUNCTION
```

### g_structtbl[0] (room type):
```
name = "ROOM"
num_members = 2
members[0] = { name="TEMP", type=T_NBR, offset=0, size=8 }
members[1] = { name="NAME", type=T_STR, offset=8, size=20 }
total_size = 29 (8 + 21, rounded up for alignment)
```

### g_vartbl entries when function runs:

| Index | Name | Type | Size | val.s |
|-------|------|------|------|-------|
| G1 | "THISREADING\x1EN" | T_INT | 8 | (integer value) |
| G2 | "THISREADING\x1EDATA" | T_STRUCT | 0 | → 32-byte block |
| L1 | "N" | T_INT\|T_PTR | 8 | → G1's value |
| L2 | "DATA" | T_STRUCT\|T_PTR | 0 | → G2's data block |

## Summary: Key Design Decisions

1. **One vartbl entry per variable** - Members are NOT individual variables
2. **Type definitions separate from instances** - `g_structtbl` holds metadata
3. **Contiguous memory blocks** - Efficient for arrays and memory operations
4. **Offset-based member access** - Calculated at runtime, no pointer chasing
5. **Alignment enforced** - 8-byte boundary for numeric types
6. **Nested structures supported** - Via recursive type references
7. **STATIC uses mangled names** - With `\x1e` separator to avoid dot conflicts

Edited 2026-01-02 19:58 by matherp
 
twofingers

Guru

Joined: 02/06/2014
Location: Germany
Posts: 1715
Posted: 10:17am 02 Jan 2026
Copy link to clipboard 
Print this post

Thanks Peter,
I really appreciate getting such a comprehensive overview! It will certainly be very useful for many here!
Perhaps this (and other internal details, e.g., "Calltable, etc.") could be included in a separate appendix to the manual?
Just a suggestion.
Kind regards
Michael

Other interesting topics would be, for example, an explanation of how each storage type is used, how much buffer memory MP3 playback (WAV, FLAC) requires, etc.

These are things I often miss, and others apparently don't.
Edited 2026-01-02 21:41 by twofingers
causality ≠ correlation ≠ coincidence
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 5585
Posted: 11:59am 02 Jan 2026
Copy link to clipboard 
Print this post

Thanks Peter !

I assume the structure and member definitions find place in the heap. Correct ?

Volhout
PicomiteVGA PETSCII ROBOTS
 
     Page 6 of 7    
Print this page
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2026