PowerBASIC provides built-in string operations for concatenation, assignment, length retrieval, pointer access, and comparison. All strings are NUL-terminated (C-compatible) and stored in stack-local or heap-allocated buffers.
result$ = a$ + b$ [+ c$ ...]dest$ = expr$LEN(string$)STRPTR(string$)VARPTR(variable)a$ = b$ a$ < b$ a$ > b$
| Parameter | Description |
|---|---|
string$ | Any valid STRING expression or variable |
variable | Any variable (STRING or numeric); VARPTR returns its address |
a$, b$, c$ | STRING operands to concatenate |
result$ = a$ + b$ [+ c$ ...]pb_cg_emit_string_concat_to_heap_temp (pb_codegen.c:3648)LOCAL a$, b$, c$ AS STRING a$ = "Hello" b$ = " World" c$ = a$ + b$ ' c$ = "Hello World"
xor rax, rax ; For each part: get address -> RAX, length -> R10 mov [rbp - ptr_offset_i], rax ; save part pointer mov [rbp - len_offset_i], r10 ; save part length add [rbp - total_bytes], r10 ; total += len
mov rcx, [rbp - total_bytes] add rcx, 8 ; + padding for NUL call [__imp_malloc] ; allocate buffer mov [rbp - out_ptr], rax ; For each part: mov rcx, [rbp - out_ptr] add rcx, [rbp - write_pos] ; dest = base + pos mov rdx, [rbp - ptr_offset_i] ; src = part data mov r8, [rbp - len_offset_i] ; count = part length call [__imp_memcpy] ; copy add [rbp - write_pos], r8 ; pos += len ; NUL-terminate: mov r11, [rbp - out_ptr] add r11, [rbp - total_bytes] mov byte [r11], 0
pb_cg_emit_string_expr_to_descriptor (pb_codegen.c:3910)LOCAL s AS STRING s = "Hello World" ' literal assignment s = someFunction$() ' expression result assignment
; String literal assignment: lstrcpynA lea rcx, [rbp - dest_offset] ; dest buffer mov rdx, [rbp - print_ptr_offset] ; source ptr mov r8, capacity ; max chars call [__imp_lstrcpynA] ; String expression assignment: malloc + memcpy + descriptor update
LEN(string$)pb_cg_emit_len_builtin (pb_codegen.c:4108)Returns the number of characters in string$ (excluding NUL terminator). For a string literal the length is a compile-time constant.
LOCAL s, n AS STRING s = "Hello" n = LEN(s) ' n = 5
; String literal: constant mov rax, <literal_length> ; Local STRING: load from descriptor mov rax, [rbp - length_offset] ; length slot in frame ; STATIC/GLOBAL STRING: load from static data mov rax, [<label>_len]
STRPTR(string$)pb_cg_emit_strptr_builtin (pb_codegen.c:4130)Returns the memory address of the string data (a pointer to the first character). Useful when calling external DLL functions that expect a char*.
LOCAL s AS STRING, p AS DWORD s = "Hello" p = STRPTR(s) ' p = address of 'H'
; Local STRING: load data pointer from descriptor mov rax, [rbp - offset] ; string data pointer ; BYREF STRING: dereference pointer mov r11, [rbp - offset] ; get pointer-address mov rax, [r11] ; deref to data pointer ; Concatenation expression: scratch buffer address lea rax, [rbp - asciiz_scratch_offset]
VARPTR(variable)pb_cg_emit_varptr_builtin (pb_codegen.c:4140)Returns the memory address of any variable. For a STRING variable this returns the address of the string descriptor, not the string data (use STRPTR for that).
LOCAL x AS LONG, p AS DWORD x = 42 p = VARPTR(x) ' p = stack address of x
; Stack local: LEA for address lea rax, [rbp - var_offset] ; BYREF parameter: already an address mov rax, [rbp - param_offset] ; STATIC/GLOBAL: LEA for static label lea rax, [static_label] ; Array element: compute element address mov rax, r11 ; from pb_cg_emit_array_address
pb_cg_emit_string_comparison_expr (pb_codegen.c:4930)String comparison is case-sensitive and lexicographic. It first compares the common prefix via memcmp, then falls back to length comparison if the prefix is identical. Supports all relational operators: =, <>, <, >, <=, >=.
LOCAL a$, b$ AS STRING a$ = "Apple" b$ = "Banana" IF a$ < b$ THEN PRINT "Apple comes first" ' true
; Compare first min(lenL, lenR) bytes with memcmp mov rcx, [rbp - left_ptr] mov rdx, [rbp - right_ptr] mov r8, min_len call [__imp_memcmp] movsxd rax, eax ; sign-extend 32-bit result cmp rax, 0 jne __pb_str_cmp_ready_N ; different -> use memcmp result ; Prefix equal, compare lengths: mov rax, [rbp - left_len] cmp rax, [rbp - right_len] ; 0 if equal, -1 if left shorter, 1 if left longer ; Then comparison jump: je/jne/jl/jg/jle/jge __pb_str_true_N