diff --git a/doc/manual/cache/CatPgProgrammer.wakka b/doc/manual/cache/CatPgProgrammer.wakka index 05a7331a6e..1e70c61bc7 100644 --- a/doc/manual/cache/CatPgProgrammer.wakka +++ b/doc/manual/cache/CatPgProgrammer.wakka @@ -32,7 +32,7 @@ {{fbdoc item="keyword" value="ProPgFixLenArrays|Fixed-length Arrays"}} {{fbdoc item="keyword" value="ProPgVarLenArrays|Variable-length Arrays"}} {{fbdoc item="keyword" value="ProPgArrayIndex|Array Indexing"}} - Passing Arrays to Procedures + {{fbdoc item="keyword" value="ProPgPassingArrays|Passing Arrays to Procedures"}} {{fbdoc item="subsect" value="Pointers"}} {{fbdoc item="keyword" value="ProPgPointers|Overview"}} @@ -42,9 +42,10 @@ {{fbdoc item="keyword" value="ProPgImplicitdeclarations|Implicit Declarations"}} {{fbdoc item="keyword" value="ProPgInitialization|Initialization"}} {{fbdoc item="keyword" value="ProPgStorageClasses|Storage Classes"}} - Variable Lifetime {{fbdoc item="keyword" value="ProPgVariableScope|Variable Scope"}} - Namespaces + {{fbdoc item="keyword" value="ProPgVariableLifetime|Simple Variable Lifetime vs Scope"}} + {{fbdoc item="keyword" value="ProPgObjectLifetime|Dynamic Object and Data Lifetime"}} + {{fbdoc item="keyword" value="ProPgNamespaces|Namespaces"}} {{fbdoc item="keyword" value="ProPgVarProcLinkage|Variable and Procedure Linkage"}} {{fbdoc item="section" value="User Defined Types"}} @@ -56,8 +57,8 @@ {{fbdoc item="keyword" value="ProPgProperties|Properties"}} {{fbdoc item="keyword" value="ProPgMemberAccessRights|Member Access Rights"}} {{fbdoc item="keyword" value="ProPgOperatorOverloading|Operator Overloading"}} - Iterators - New and Delete + {{fbdoc item="keyword" value="ProPgTypeIterators|Iterators"}} + {{fbdoc item="keyword" value="ProPgNewDelete|New and Delete"}} {{fbdoc item="keyword" value="ProPgTypeObjects|Types as Objects"}} <<>>{{fbdoc item="section" value="Statements and Expressions"}} Assignments @@ -71,7 +72,7 @@ {{fbdoc item="keyword" value="ProPgReturnValue|Returning a Value"}} Procedure Scopes {{fbdoc item="keyword" value="ProPgCallingConventions|Calling Conventions"}} - Recursion + {{fbdoc item="keyword" value="ProPgRecursion|Recursion"}} Constructors and Destructors {{fbdoc item="keyword" value="ProPgProcedurePointers|Pointers to Procedures"}} {{fbdoc item="keyword" value="CatPgVarArg|Variable Arguments"}} diff --git a/doc/manual/cache/DevArrays.wakka b/doc/manual/cache/DevArrays.wakka new file mode 100644 index 0000000000..7006c2c9f3 --- /dev/null +++ b/doc/manual/cache/DevArrays.wakka @@ -0,0 +1,143 @@ +{{fbdoc item="title" value="Arrays"}}---- +An array in fbc is a collection of elements where each element has the same type and is accessed with an index in to the array. + +Example: +%%(freebasic) + '' one dimensional array (1 index) + dim a(1 to 10) as integer + print a(1) '' first element (integer) + print a(10) '' last element (integer) + + '' two dimensional array (2 indexes) + dim b(1 to 2, 1 to 5) as integer + print b(1,1) '' first element (integer) + print b(2,5) '' last element (integer) +%% + +{{fbdoc item="section" value="Array Dimensions and Bounds"}} + +The number of dimensions refers to the number of indexes that are required to be given to access an element of an array. The number of dimensions may or may not be part of the declaration. If the number of dimensions are known at compile time within the scope that the array is used, fbc can check and error if the wrong number of indexes are specified. + +The bounds of an array are the allowable minimum and maximum index values for each dimension. Accessing an array element with an index or indexes that are outside the array bounds of a dimension is undefined behaviour. + +fbc can check and error if an index or indexes (access) are outside the bounds of the array when compiled with '-exx' or '-earray' compile options. If the array bounds are compile-time constant, and the array access is compile-time constant, fbc can check if an array access is outside the bounds of the array at compile time. Otherwise, the array bounds check must occur at run-time if either the bounds or the access is non-constant. + +{{fbdoc item="section" value="Fixed dimension versus unknown dimension"}} + +The number of dimensions may be fixed or unknown. fbc will attempt to determine the number of dimensions an array is expected to have based on declarations for the array. If fbc cannot determine the number of dimensions at compile time, the number of dimensions will become fixed on first redimension of the array at run time. + +Example: fixed 2 dimension, dynamic bounds +%%(freebasic) +dim a(any, any) as integer +redim a(1 to 2, 1 to 5) +%% + +Example: Dynamic dimension, dynamic bounds +%%(freebasic) +dim a() as integer + +'' then only one of on first time use ... +redim a(1 to 10) +redim a(1 to 2, 1 to 5) +redim a(1 to 2, 1 to 5, 1 to 3) +%% + +Once number of dimensions are known to fbc, within the scope of the array, fbc will error if any access to the error has wrong number of dimensions. Or if still unknown at compile time, as in the case of an array passed as argument to a procedure and resized, the number of dimensions become fixed at run time. + +{{fbdoc item="section" value="Fixed bounds versus Dynamic bounds"}} + +Fixed length arrays have array bounds that are known at compile-time. Dynamic (or variable length) arrays have array bounds that can be altered and resized at run-time, and may be considered unknown at compile time. + +Example: fixed (constant) bounds and constant access +%%(freebasic) +dim a(1 to 10) as integer +print a(11) '' compile time array out-of-bounds +%% + +Example: fixed bounds and non-constant access +%%(freebasic) +dim a(1 to 10) as integer +dim i as integer +print a(i) '' run time array out-of-bounds +%% + +Example: dynamic bounds +%%(freebasic) +dim a(any) as integer '' 1 dimensional, empty +redim a(1 to 10) '' resized to 10 elements +print a(11) '' run time array out-of-bounds +print a(i) '' run time array out-of-bounds +%% + +{{fbdoc item="section" value="Static Array versus Dynamic Array"}} + +Arrays may have static or dynamic memory allocation. The descriptor may be static or dynamic, and memory space for the data may be static or dynamic. The terms static and dynamic may be overused and so may lose meaning when describing an array. In this context static versus dynamic should not be confused with fixed-length or variable-length. In this context we are referring to how and where the array descriptor and it's associated data are allocated in memory, and to some extent the life time of the variable. + +For an array descriptor to be valid, it must be initialized. An uninitialized array descriptor will almost certainly lead to undefined behaviour at run time. + +The array descriptor itself may be allocated in .bss, .data, on stack or on heap, depending on the declaration of the array. Though typically not in .bss section because an array descriptor usually must be initialized to some non-zero default values to be usable. + +The array's data may be located in .bss section, .data section, on stack or on heap, depending on the declaration of the array. In fbc's current implementation, the array data for variable-length arrays is always allocated on the heap (i.e. malloc()). + +{{fbdoc item="section" value="Array Descriptor"}} + +At compile time, fbc allocates an array descriptor to store and track information about the array. + +From ##./inc/fbc-int/array.bi##): +%%(freebasic) + const FB_MAXDIMENSIONS as integer = 8 + + type FBARRAYDIM + dim as uinteger elements '' number of elements + dim as integer lbound '' dimension lower bound + dim as integer ubound '' dimension upper bound + end type + + type FBARRAY + dim as any ptr index_ptr '' @array(0, 0, 0, ... ) + dim as any ptr base_ptr '' start of memory at array lowest bounds + dim as uinteger size '' byte size of allocated contents + dim as uinteger element_len '' byte size of single element + dim as uinteger dimensions '' number of dimensions + dim as FBARRAYDIM dimTb(0 to FB_MAXDIMENSIONS-1) + end type +%% + +If the number of dimensions is unknown at compile time, then the full ##FB_MAXDIMENSIONS## is allocated in the ##dimTb()## field. Otherwise, if the number dimensions is known at compile time, then only the number of dimensions needed are allocated. Therefore the allocated ##FBARRAY## data may be smaller than the declared ##FBARRAY## structure. + +If an array is passed as argument to a procedure, an array descriptor is allocated. However, if the array is static, fixed length, and never passed as an argument, then all information about the array is known at compile time, including memory locations, and the allocation of a descriptor is optimized out, since all expressions involving the array are compile time constant. + +The array descriptor may also be allocated at run time, as would be in the case of allocating a new UDT containing a variable-length array field member. + +{{fbdoc item="subsect" value="FBARRAY.index_ptr"}} +Pointer to the array data ##@array(0, 0, ...)##. This pointer may be outside of the actual array data as a kind of virtual pointer to use when calculating offsets using indexes in to the array. + +{{fbdoc item="subsect" value="FBARRAY.base_ptr"}} +Pointer to the array's memory at the array's lowest bound. For variable-length arrays allocated at run time, this points to the allocated memory region (i.e. malloc) + +{{fbdoc item="subsect" value="FBARRAY.size"}} +Total size in bytes of the array data. Size is equal to total number of elements in the array (all dimensions) multiplied by element length. i.e. ##size = dimTb(0).elements * element_len + dimTb(1).elements * element_len + ...## + +{{fbdoc item="subsect" value="FBARRAY.element_len"}} +Size in bytes of an individual element. Must be set to non-zero value. + +{{fbdoc item="subsect" value="FBARRAY.dimensions"}} +Number of valid dimensions in the dimTb() table. A value of zero (0) indicates that dimTb() has ##FB_MAXDIMENSIONS## avaiable, but the array does not yet have number of dimensions defined. On first REDIM, the number of dimensions will be set. + +{{fbdoc item="subsect" value="FBARRAY.dimTb()"}} +dimTb() is an array of ##FBARRAYDIM## to indicate the bounds of each dimension. + +If the number of dimensions is unknown at compile time, then the full ##FB_MAXDIMENSIONS## is allocated in the ##dimTb()## field. Otherwise, if the number dimensions is known at compile time, then only the number of dimensions needed are allocated. Therefore the allocated ##FBARRAY## data may be smaller than the declared ##FBARRAY## structure. + +{{fbdoc item="subsect" value="FBARRAYDIM.elements"}} +Number of elements in the dimension. i.e. ##(ubound-lbound+1)## + +{{fbdoc item="subsect" value="FBARRAYDIM.lbound"}} +Lower bound is the lowest valid index in this dimension. + +{{fbdoc item="subsect" value="FBARRAYDIM.ubound"}} +Upper bound is the highest valid index in this dimension. + + +{{fbdoc item="back" value="DevToc|FreeBASIC Developer Information"}} +{{fbdoc item="back" value="DocToc|Table of Contents"}} diff --git a/doc/manual/cache/DevBuildConfig.wakka b/doc/manual/cache/DevBuildConfig.wakka index 93e0ed88d4..2dbe28292b 100644 --- a/doc/manual/cache/DevBuildConfig.wakka +++ b/doc/manual/cache/DevBuildConfig.wakka @@ -79,6 +79,12 @@ make install-rtlib install-gfxlib2 TARGET=i686-w64-mingw32 - ##ENABLE_STANDALONE=1## Build a standalone FB setup instead of the normal Unix-style setup, see also: [[DevNormalVsStandalone|the standalone vs. normal comparison]]. This causes the makefile to use the standalone directory layout and to use ##-d ENABLE_STANDALONE## when building the compiler. + - ##ENABLE_STRIPALL=1## + Enable the ##[[CompilerOptstrip|-strip]]## compiler option by default. If ##ENABLE_STRIPALL=1## is not given, this is the default for dos/win. + + - ##ENABLE_STRIPALL=0## + Enable the ##[[CompilerOptnostrip|-nostrip]]## compiler option by default. If ##ENABLE_STRIPALL=1## is not given, this is the default for linux (basically, everything other target besides dos.win). + - ##ENABLE_PREFIX=1## This causes the makefile to use ##-d ENABLE_PREFIX=$(prefix)## when building the compiler. @@ -99,6 +105,9 @@ make install-rtlib install-gfxlib2 TARGET=i686-w64-mingw32 - ##-d ENABLE_STANDALONE## This makes the compiler behave as a standalone tool that cannot rely on the system to have certain programs or libraries. See [[DevNormalVsStandalone|the normal vs. standalone comparison]] for more information. + - ##-d ENABLE_STRIPALL## + Enable the ##[[CompilerOptstrip|-strip]]## by default, otherwise ##[[CompilerOptnostrip|-nostrip]]## is default. + - ##-d ENABLE_SUFFIX=foo## This makes the compiler append the given suffix to the ##lib/freebasic/## directory name when searching for its own ##lib/freebasic/## directory. For example, ##-d ENABLE_SUFFIX=-0.24## causes it to look for ##lib/freebasic-0.24/## instead of ##lib/freebasic/##. Corresponding the ENABLE_SUFFIX=foo makefile option, this adjust the compiler to work in the new directory layout. diff --git a/doc/manual/cache/DevToc.wakka b/doc/manual/cache/DevToc.wakka index 3549941186..d3823f5918 100644 --- a/doc/manual/cache/DevToc.wakka +++ b/doc/manual/cache/DevToc.wakka @@ -40,6 +40,7 @@ This area of the Wiki is for documenting everything about the compiler and the r {{fbdoc item="keyword" value="DevFbcParserSymbols|Symbols"}} {{fbdoc item="keyword" value="DevFbcTypes|Representation of data types"}} + {{fbdoc item="keyword" value="DevArrays|Arrays"}} {{fbdoc item="keyword" value="DevSelectCase|SELECT CASE"}} {{fbdoc item="keyword" value="ProPgProfiling|Profiling FB programs"}} {{fbdoc item="keyword" value="DevStructLayout|Structure packing/field alignment"}} diff --git a/doc/manual/cache/KeyPgDots.wakka b/doc/manual/cache/KeyPgDots.wakka index e0d4772b13..a802fa9a49 100644 --- a/doc/manual/cache/KeyPgDots.wakka +++ b/doc/manual/cache/KeyPgDots.wakka @@ -27,6 +27,8 @@ Used in place of procedure parameter to pass a variable number of arguments, or Using an ellipsis behind the last parameter in a ##[[KeyPgPpdefine|#define]]## or ##[[KeyPgPpmacro|#macro]]## declaration allows creation of a variadic macro. This means it is possible to pass any number of arguments to the //variadic_parameter//, which can be used in the //body// as if it was a normal macro parameter. The //variadic_parameter// will expand to the full list of arguments passed to it, including commas, and can also be completely empty. + **Note:** To distinguish between the different arguments passed by //variadic_parameter//, you can first convert //variadic_parameter// to a string using the ##[[KeyPgOpPpStringize|Operator # (Preprocessor Stringize)]]##, then differentiate in this string (//#variadic_parameter//) each passed argument by locating the separators (usually a comma). + __Array Upper Bound__ Using an ellipsis in place of the upper bound in an array declaration causes the upper bound to be set according to the data that appears in the ##//expression_list//##. When the ellipsis is used in this manner, an initializer must appear, and cannot be ##[[KeyPgAny|Any]]##. diff --git a/doc/manual/cache/KeyPgExtendsZstring.wakka b/doc/manual/cache/KeyPgExtendsZstring.wakka index def82df5d3..e3c82501b9 100644 --- a/doc/manual/cache/KeyPgExtendsZstring.wakka +++ b/doc/manual/cache/KeyPgExtendsZstring.wakka @@ -89,7 +89,7 @@ End Destructor Operator Len (Byref v As vZstring) As Integer Return Len(Type(v)) '' found nothing better than this ('vZstring.l' being private) -End Operator +End Operator '' (or: 'Return Len(Str(v))') Dim As vZstring v = "FreeBASIC" Print "'" & v & "'", Len(v) @@ -114,7 +114,7 @@ v[0] = Asc("-") Print "'" & v & "'", Len(v) 'Print "'" & Right(v, 5) & "'" '' 'Right' does not yet support types with 'Extends Zstring' -Print "'" & Right(Str(v), 5) & "'" '' workaround +Print "'" & Right(Str(v), 5) & "'" '' workaround (or: 'Right(Type(v), 5)') Sleep %% diff --git a/doc/manual/cache/KeyPgPperror.wakka b/doc/manual/cache/KeyPgPperror.wakka index 50f9b7a569..3090066807 100644 --- a/doc/manual/cache/KeyPgPperror.wakka +++ b/doc/manual/cache/KeyPgPperror.wakka @@ -9,9 +9,11 @@ Preprocessor diagnostic directive The display message {{fbdoc item="desc"}} - ##**#error**## stops compiling and displays ##//error_text//## when compiler finds it. + ##**#error**## interrupts compiling to display ##//error_text//## when compiler finds it, and then parsing continues. This keyword must be surrounded by an ##[[KeyPgPpif|#if]] ////## ...##[[KeyPgPpendif|#endif]]##, so the compiler can reach ##**#error**## only if ##////## is met. + + In any case, the final status will be "Failed to compile". {{fbdoc item="ex"}} {{fbdoc item="filename" value="examples/manual/prepro/error.bas"}}%%(freebasic) diff --git a/doc/manual/cache/PrintToc.wakka b/doc/manual/cache/PrintToc.wakka index c55843e08e..f6f1fb10f5 100644 --- a/doc/manual/cache/PrintToc.wakka +++ b/doc/manual/cache/PrintToc.wakka @@ -102,7 +102,8 @@ [[KeyPgAccess|ACCESS]] [[KeyPgAcos|ACOS]] [[KeyPgAddGfx|ADD (Graphics PUT)]] - [[KeyPgAlias|ALIAS]] + [[KeyPgAlias|ALIAS (Name)]] + [[KeyPgAliasModifier|ALIAS (Modifier)]] [[KeyPgAllocate|ALLOCATE]] [[KeyPgAlphaGfx|ALPHA (Graphics PUT)]] [[KeyPgOpAnd|AND]] @@ -185,6 +186,11 @@ [[KeyPgCurdir|CURDIR]] [[KeyPgCushort|CUSHORT]] [[KeyPgCustomgfx|CUSTOM (Graphics PUT)]] + [[KeyPgCvaArg|CVA_ARG]] + [[KeyPgCvaCopy|CVA_COPY]] + [[KeyPgCvaEnd|CVA_END]] + [[KeyPgCvaList|CVA_LIST]] + [[KeyPgCvaStart|CVA_START]] [[KeyPgCvd|CVD]] [[KeyPgCvi|CVI]] [[KeyPgCvl|CVL]] @@ -255,6 +261,8 @@ [[KeyPgExp|EXP]] [[KeyPgExport|EXPORT]] [[KeyPgExtends|EXTENDS]] + [[KeyPgExtendsWstring|EXTENDS WSTRING]] + [[KeyPgExtendsZstring|EXTENDS ZSTRING]] [[KeyPgExtern|EXTERN]] [[KeyPgExternBlock|EXTERN...END EXTERN]] @@ -773,6 +781,7 @@ [[ProPgFixLenArrays|Fixed-length Arrays]] [[ProPgVarLenArrays|Variable-length Arrays]] [[ProPgArrayIndex|Array Indexing]] + [[ProPgPassingArrays|Passing Arrays to Procedures]] {{fbdoc item="subsect" value="Pointers"}} [[ProPgPointers|Overview]] @@ -783,6 +792,9 @@ [[ProPgInitialization|Initialization]] [[ProPgStorageClasses|Storage Classes]] [[ProPgVariableScope|Variable Scope]] + [[ProPgVariableLifetime|Simple Variable Lifetime vs Scope]] + [[ProPgObjectLifetime|Dynamic Object and Data Lifetime]] + [[ProPgNamespaces|Namespaces]] [[ProPgVarProcLinkage|Variable and Procedure Linkage]] {{fbdoc item="subsect" value="User Defined Types"}} @@ -794,6 +806,8 @@ [[ProPgProperties|Properties]] [[ProPgMemberAccessRights|Member Access Rights]] [[ProPgOperatorOverloading|Operator Overloading]] + [[ProPgTypeIterators|Iterators]] + [[ProPgNewDelete|New and Delete]] [[ProPgTypeObjects|Types as Objects]] {{fbdoc item="subsect" value="Statements and Expressions"}} @@ -805,6 +819,7 @@ [[ProPgPassingArguments|Passing Arguments to Procedures]] [[ProPgReturnValue|Returning a Value]] [[ProPgCallingConventions|Calling Conventions]] + [[ProPgRecursion|Recursion]] [[ProPgProcedurePointers|Pointers to Procedures]] [[CatPgVarArg|Variable Arguments]] @@ -961,6 +976,12 @@ [[CompilerOptdll|-dll]] [[CompilerOptdylib|-dylib]] [[CompilerOpte|-e]] + [[CompilerOptearray|-earray]] + [[CompilerOpteassert|-eassert]] + [[CompilerOptedebug|-edebug]] + [[CompilerOptedebuginfo|-edebuginfo]] + [[CompilerOptelocation|-elocation]] + [[CompilerOptenullptr|-enullptr]] [[CompilerOptex|-ex]] [[CompilerOptexx|-exx]] [[CompilerOptexport|-export]] @@ -981,6 +1002,7 @@ [[CompilerOptnodeflibs|-nodeflibs]] [[CompilerOptnoerrline|-noerrline]] [[CompilerOptnoobjinfo|-noobjinfo]] + [[CompilerOptnostrip|-nostrip]] [[CompilerOpto|-o < name >]] [[CompilerOptoptimization|-O < level >]] [[CompilerOptp|-p < name >]] @@ -996,6 +1018,7 @@ [[CompilerOpts|-s < name >]] [[CompilerOptshowincludes|-showincludes]] [[CompilerOptstatic|-static]] + [[CompilerOptstrip|-strip]] [[CompilerOptt|-t < value >]] [[CompilerOpttarget|-target < platform >]] [[CompilerOptv|-v]] diff --git a/doc/manual/cache/ProPgArrays.wakka b/doc/manual/cache/ProPgArrays.wakka index 4958657de4..040f4c58d7 100644 --- a/doc/manual/cache/ProPgArrays.wakka +++ b/doc/manual/cache/ProPgArrays.wakka @@ -67,6 +67,8 @@ Dim as integer multidim(1 to 2,1 to 5) = {{0,0,0,0,0},{0,0,0,0,0}} {{fbdoc item="see"}} - [[ProPgFixLenArrays|Fixed-length Arrays]] - [[ProPgVarLenArrays|Variable-length Arrays]] + - [[ProPgArrayIndex|Array Indexing]] + - [[ProPgPassingArrays|Passing Arrays to Procedures]] - [[ProPgVariableScope|Variable Scope]] {{fbdoc item="back" value="CatPgProgrammer|Programmer's Guide"}} \ No newline at end of file diff --git a/doc/manual/cache/ProPgNamespaces.wakka b/doc/manual/cache/ProPgNamespaces.wakka new file mode 100644 index 0000000000..f615e86f85 --- /dev/null +++ b/doc/manual/cache/ProPgNamespaces.wakka @@ -0,0 +1,151 @@ +{{fbdoc item="title" value="Namespaces"}}---- +**Namespace**, a container for identifiers so that they don't conflict with those in other **Namespaces** or the global scope. + +{{fbdoc item="section" value="Syntax"}}## + **Namespace** //identifier// [ [[KeyPgAlias|Alias]] "//aliasname//" ] + //statements// + **End Namespace** +## +{{fbdoc item="section" value="Parameters"}} + ##//identifier//## + The name of the Namespace (including nested names specifier). + ##//aliasname//## + An alternate external name for the Namespace. + +{{fbdoc item="section" value="Description"}} + Namespaces are declaration fields that allow to delimit the search for the names of identifiers by the compiler. Their purpose is essentially to group the identifiers logically and to avoid name conflicts between several parts of the same project. + This type of conflict stems from the fact that only one global scope is provided by default, in which there should be no name conflict. With Namespaces, this type of problem can be more easily avoided, because defining global objects in the global scope can be avoid. + + Namespaces are not allowed to contain code directly, only inside procedures declared in that Namespace. That is because a Namespace is not a scope, it is not something that is executed, it is just something that can be used to hold declarations. + + Any variable declared in Namespace is implicitly static and visible throughout the entire program (##[[KeyPgStatic|Static]]## and ##[[KeyPgShared|Shared]]## keywords are useless). Therefore only an initializer with a constant is authorized. + +{{fbdoc item="section" value="Usage"}} + Unlike another declarative region such as a ##[[KeyPgType|Type]]##, a Namespace can be split into several pieces. The first piece serves as declaration, and the following ones as extensions. The syntax for a Namespace extension is exactly the same as that for the declaration part. + Identifiers declared or defined within the same Namespace must not conflict. They may have the same names, but only as part of the overloading. A Namespace therefore behaves exactly like the declaration fields of Types and the global scope. + + Access to Namespace identifiers is through the resolution operator ("."), by prefixing the name of the identifier to use from the name of its Namespace. However, this prefixing is useless inside the Namespace itself, just like members inside their Type. + Namespace member procedures can be defined inside this space. They can also be set outside this space, if the resolution operator is used (prefixing from the name of its Namespace). The procedures thus defined must appear after their declarations in the Namespace. + + It is possible to define a Namespace within another Namespace. However, this declaration must occur at the outermost declarative level of the Namespace that will contain the Namespace. Namespace declarations can not be put inside a procedure body or inside a Type block. + + When a Namespace has a very complicated name, it may be advantageous to define an alias for that name. The alias will then have a simpler name. + Names given to Namespace aliases must not conflict with the names of other identifiers in the same Namespace, whether this is the global scope or not. + + **Note:** The parser allows to define anonymous Namespaces (without ##//identifier//## term), but this is the only similarity with the actual ""C++"" capability: The FB compiler automatically generates multiple separate anonymous Namespaces instead of one only per module in such a case. + The FB anonymous Namespaces are almost unusable because all their declarations are inaccessible, even from the body of the module that contains them. Apart from encapsulating module constructors/destructors also inside, nothing else can be done with them. + + __'Using (Namespaces)' command__ + ##[[KeyPgUsing|Using (Namespaces)]]## allows to use a identifier from a Namespace in a simplified way, without having to specify its full name (that is, the Namespace name followed by the "." operator then the identifier name). + Each Using command allows to directly use all the identifiers of the referred Namespace. + + **""-""** Syntax: + ##**Using** //identifier// [, //identifier// [, ...] ]## + + **""-""** Parameters: + ##//identifier//##: The name of the Namespace to use. + + **""-""** Usage: + After a Using command, it is still possible to use the full names of the identifiers from a Namespace, but this is no longer necessary. The Using commands are valid from the line where they are declared until the end of the current scope block. + If a Namespace is extended after a Using directive, the identifiers defined in the Namespace extension can be then used exactly as the identifiers defined before the using directive (that is, without the full expression of their Namespace names). + + When entering Using command(s) for several Namespace names, name conflicts may occur. In this case, no error is reported from the Using command(s), but an error occurs if one of the identifiers for which there is a conflict is used (using full name of the expected identifier solves the conflict). + +{{fbdoc item="section" value="Example"}} + Namespace extension: + {{fbdoc item="filename" value="examples/manual/proguide/namespaces/extension1.bas"}}%%(freebasic) +Namespace A ' Declaration of Namespace A + Dim As Integer i +End Namespace + +Namespace B ' Declaration of Namespace B + Dim As Integer i +End Namespace + +Namespace A ' Extension of Namespace A + Dim As Integer j +End Namespace +%% + Access to Namespace members: + {{fbdoc item="filename" value="examples/manual/proguide/namespaces/access.bas"}}%%(freebasic) +Dim As Integer i ' Declare i in the global scope + +Namespace A + Dim As Integer i = 2 ' Declare i in Namespace A + Dim As Integer j = 3 ' Declare j in Namespace A +End Namespace + +i = 1 ' Use i from global scope (.i) +A.i = 4 ' Use i from Namespace A (A.i) +%% + External definition of a function declared in a Namespace: + {{fbdoc item="filename" value="examples/manual/proguide/namespaces/externdef.bas"}}%%(freebasic) +Namespace A + Declare Function f () As Integer ' Declaration of f() in Namespace A (A.f()) +End Namespace + +Function A.f () As Integer ' Definition of f() from Namespace A (A.f()) + Return 0 +End Function +%% + Definition of nested Namespace: + {{fbdoc item="filename" value="examples/manual/proguide/namespaces/nested.bas"}}%%(freebasic) +Namespace A + Dim As Integer i ' (A.i) + Namespace B + Dim As Integer j ' (A.B.j) + End Namespace +End Namespace +%% + Access with 'Using (Namespaces)' command: + {{fbdoc item="filename" value="examples/manual/proguide/namespaces/using.bas"}}%%(freebasic) +Namespace A + Dim As Integer i ' Declaration of A.i + Dim As Integer j ' Declaration of A.j +End Namespace + +Using A ' Namespace A identifiers are also used +i = 1 ' Equivalent to A.i +j = 1 ' Equivalent to A.j +%% + Extension of Namespace after 'Using (Namespace)' command: + {{fbdoc item="filename" value="examples/manual/proguide/namespaces/extension2.bas"}}%%(freebasic) +Namespace A + Dim As Integer i +End Namespace + +Using A + +Namespace A + Dim As Integer j +End Namespace + +i = 0 ' Initialize A.i +j = 0 ' Initialize A.j +%% + Conflict between local identifiers with 'Using (Namespaces)' command: + {{fbdoc item="filename" value="examples/manual/proguide/namespaces/conflict.bas"}}%%(freebasic) +Namespace A + Dim As Integer i ' Declare A.i + Dim As Integer j ' Declare A.j +End Namespace + +Namespace B + Dim As Integer i ' Declare B.i + Dim As Integer j ' Declare B.j + Using A ' A.i/j and B.i/j are in conflict, but no error is given +End Namespace + +Dim As Integer j ' Declare also j the global scope + +Using B +'i = 1 ' error: Ambiguous symbol access, explicit scope resolution required (between B.i and A.i) +B.i = 1 ' ambiguity resolution solved by using full name +j = 2 ' ambiguity (between .j, B.j, A.j) solved by compiler, by choosing override .j in the global scope +%% +{{fbdoc item="section" value="See also"}} + - [[KeyPgNamespace|Namespace]] + - [[KeyPgUsing|Using (Namespaces)]] + - [[KeyPgScope|Scope...End Scope]] + +{{fbdoc item="back" value="CatPgProgrammer|Programmer's Guide"}} \ No newline at end of file diff --git a/doc/manual/cache/ProPgNewDelete.wakka b/doc/manual/cache/ProPgNewDelete.wakka new file mode 100644 index 0000000000..f83bb84d19 --- /dev/null +++ b/doc/manual/cache/ProPgNewDelete.wakka @@ -0,0 +1,301 @@ +{{fbdoc item="title" value="New and Delete"}}---- +The different operators **New** (//Implicit///Overload/Expression/Placement) and **Delete** (//Implicit///Overload/Statement), and all their array-versions **New[]** and **Delete[]** + +{{fbdoc item="section" value="Definition"}} + There may be confusion in the user mind between the different operators **New** and **Delete** (despite the documentation that distinguishes them from each other through some different pages): + - ##//'Operator New Implicit' (inaccessible by user)//##: + **""-""** It is a static function that only allocates memory (it is not very different from ##[[KeyPgAllocate|Allocate]]##). + - ##[[KeyPgOpNewOverload|Operator New Overload]]##: + **""-""** It is a member operator (static function) that can overload the ##//'Operator New Implicit'//## only for user-defined types. + **""-""** So the user can define its own dynamic memory allocation process part (the following process part for implicit data construction can not be modified). + - ##//'Operator Delete Implicit' (inaccessible by user)//##: + **""-""** It is a static sub that only frees the memory (it is not very different from ##[[KeyPgDeallocate|Deallocate]]##). + - ##[[KeyPgOpDeleteOverload|Operator Delete Overload]]##: + **""-""** It is a member operator (static sub) that can overload the ##//'Operator Delete Implicit'//## only for user-defined types. + **""-""** So the user can define its own memory deallocation process part (the previous process part for implicit data destruction can not be modified). + - ##[[KeyPgOpNew|Operator New Expression]]##: + **""-""** It starts by using the ##'Operator New //Implicit///Overload'## (the implicit, or the overload if exists) to allocate memory. + **""-""** Then it invokes the constructor for the right type of object. If that object contains any other objects (either embedded or as base types) those constructors as invoked as well. + **""-""** So the final result is memory allocated and object constructed. + **""-""** This operator applies to pre-defined types (except fixed-length strings) as well as user-defined types. + - ##[[KeyPgOpDelete|Operator Delete Statement]]##: + **""-""** It starts by invoking the destructor for the right type of object. If that object contains any other objects (either embedded or as base types) those destructors as invoked as well. + **""-""** Then it uses the ##'Operator Delete //Implicit///Overload'## (the implicit, or the overload if exists) to deallocate memory. + **""-""** So the final result is object destroyed and memory freed. + **""-""** This operator applies to pre-defined types (except fixed-length strings) as well as user-defined types. + - ##[[KeyPgOpPlacementNew|Operator Placement New]]##: + **""-""** It only constructs object at a specified memory address (already allocated). This operator applies to pre-defined types (except fixed-length strings) as well as user-defined types. + + + Similar definition for ##'Operator New[] //Implicit///Overload/Expression'##, ##'Operator Delete[] //Implicit///Overload/Statement'## and ##'Operator Placement New[]'##, which are only the (one-dimensional) array-versions of the previous operators (there is construction/destruction loop on the array elements). + + Instances created with ##'Operator New Overload/Expression'## must be freed with ##'Operator Delete Overload/Statement'##. + Instance array created with ##'Operator New[] Overload/Expression'## must be freed with ##'Operator Delete[] Overload/Statement'##, the array-version of ##'Operator Delete Overload/Statement'##. + User can not mix and match the different versions of the operators. + +{{fbdoc item="section" value="Algorithm (applied to user-defined types)"}} + Operator New/New[] Expression: + %% +' OPERATOR NEW/NEW[] EXPRESSION +' V +' | +' call if there is >----------------------------. +' else : +' v v +' (Operator New/New[] Implicit) (Operator New/New[] Overload) +' : : +' BASIC MEMORY ALLOCATION USER BODY +' : : +' :<-------------------------------------' +' | +' |<-------------------------------------. +' | : +' DATA FIELDS INITIALIZATION : +' OBJECT FIELDS CONSTRUCTION : +' (VPTR INITIALIZATION) : +' | : +' call if there is >-----------. : +' else : : +' v v : +' : (User Constructor) : +' : : : +' : USER BODY : +' : : : +' :<--------------------' : +' | : +' loop if array-version NEW[] >-----------------------' +' else +' v +' | +' V +%% + + Operator Delete/Delete[] Statement: + %% +' OPERATOR DELETE/DELETE[] STATEMENT +' V +' | +' |<-------------------------------------. +' | : +' (VPTR REINITIALIZATION) : +' | : +' call if there is >-----------. : +' else : : +' v v : +' : (User Destructor) : +' : : : +' : USER BODY : +' : : : +' :<--------------------' : +' | : +' OBJECT FIELDS DESTRUCTION : +' | : +' loop if array-version DELETE[] >---------------------' +' else +' v +' | +' call if there is >----------------------------. +' else : +' v v +' (Operator Delete/Delete[] Implicit) (Operator Delete/Delete[] Overload) +' : : +' BASIC MEMORY DEALLOCATION USER BODY +' : : +' :<-------------------------------------' +' | +' V +%% + + Operator Placement New/New[]: + %% +' OPERATOR PLACEMENT NEW/NEW[] +' V +' | +' |<-------------------------------------. +' | : +' DATA FIELDS INITIALIZATION : +' OBJECT FIELDS CONSTRUCTION : +' (VPTR INITIALIZATION) : +' | : +' call if there is >-----------. : +' else : : +' v v : +' : (User Constructor) : +' : : : +' : USER BODY : +' : : : +' :<--------------------' : +' | : +' loop if array-version NEW[] >-----------------------' +' else +' v +' | +' V +%% +{{fbdoc item="section" value="Example"}} + Example that uses the operators New (Overload/Expression/Placement) and Delete (Overload/Statement), and all their array-versions New[] and Delete[]: + (all the 10 operators New and Delete accessible by the user): + {{fbdoc item="filename" value="examples/manual/proguide/newdelete/operators.bas"}}%%(freebasic) +Declare Sub printArray (Byref label As String = "", array() As String) + + +Type UDT + Declare Constructor () + Declare Destructor () + Declare Operator New (Byval size As Uinteger) As Any Ptr ' Operator New Overload + Declare Operator New[] (Byval size As Uinteger) As Any Ptr ' Operator New[] Overload + Declare Operator Delete (Byval buf As Any Ptr) ' Operator Delete Overload + Declare Operator Delete[] (Byval buf As Any Ptr) ' Operator Delete[] Overload + Dim As String array (1 To 4) +End Type + +Constructor UDT () + Static As Integer n + Print " Constructor" + printArray(" init: @" & @This & " (descriptors) -> ", This.array()) + For i As Integer = Lbound(This.array) To Ubound(This.array) + This.array(i) = Chr(Asc("a") + n + i - Lbound(This.array)) + Next i + printArray(" => ", This.array()) + Print + n += Ubound(This.array)- Lbound(This.array) + 1 +End Constructor + +Destructor UDT () + Print " Destructor" + printArray(" erase: @" & @This & " (descriptors) -> ", This.array()) + Erase This.array + printArray(" => ", This.array()) + Print +End Destructor + +Operator UDT.New (Byval size As Uinteger) As Any Ptr + Print " Operator New Overload" + Dim As Any Ptr p = Allocate(size) ' Memory allocation (with passed size) + Print " memory allocation: "; + Print size & " Bytes from @" & p + Return p ' Returning memory pointer +End Operator + +Operator UDT.New[] (Byval size As Uinteger) As Any Ptr + Print " Operator New[] Overload" + Dim As Any Ptr p = Allocate(size) ' Memory allocation (with passed size) + Print " memory allocation: "; + Print size & " Bytes from @" & p + Return p ' Returning memory pointer +End Operator + +Operator UDT.Delete (Byval buf As Any Ptr) + Print " Operator Delete Overload" + Deallocate(buf) ' Memory deallocation (with passed pointer) + Print " memory deallocation: "; + Print "for @" & buf +End Operator + +Operator UDT.Delete[] (Byval buf As Any Ptr) + Print " Operator Delete[] Overload" + Deallocate(buf) ' Memory deallocation (with passed pointer) + Print " memory deallocation: "; + Print "for @" & buf +End Operator + + +Print "Operator New Expression" +Dim As UDT Ptr pu1 = New UDT ' Operator New Expression +Print "Operator Delete Statement" +Delete pu1 ' Operator Delete Statement +Sleep + +Print +Print "Operator New[] Expression" +Dim As UDT Ptr pu2 = New UDT[2] ' Operator New[] Expression +Print "Operator Delete[] Statement" +Delete[] pu2 ' Operator Delete[] Statement +Sleep + +Dim As Byte buffer(1 To 256) +Dim As Any Ptr p = @buffer(1) + +Print +Print "Operator Placement New" +Dim As UDT Ptr pu3 = New(p) UDT ' Operator Placement New +Print "User call of Destructor" +pu3->Destructor() ' User Call of Destructor +Sleep + +Print +Print "Operator Placement New[]" +Dim As UDT Ptr pu4 = New(p) UDT[2] ' Operator Placement New[] +For i As Integer = 0 To 1 + Print "User Call of Destructor" + pu4[i].Destructor() ' User Call of Destructor +Next i +Sleep + + +Sub printArray (Byref label As String = "", array() As String) + Print label & "{"; + For i As Integer = Lbound(array) To Ubound(array) + Print """" & array(i) & """"; + If i < Ubound(array) Then + Print ","; + End If + Next I + Print "}"; +End Sub +%%Output example: + %% +Operator New Expression + Operator New Overload + memory allocation: 96 Bytes from @1728352 + Constructor + init: @1728352 (descriptors) -> {"","","",""} => {"a","b","c","d"} +Operator Delete Statement + Destructor + erase: @1728352 (descriptors) -> {"a","b","c","d"} => {"","","",""} + Operator Delete Overload + memory deallocation: for @1728352 +%% + %% +Operator New[] Expression + Operator New[] Overload + memory allocation: 200 Bytes from @1728352 + Constructor + init: @1728360 (descriptors) -> {"","","",""} => {"e","f","g","h"} + Constructor + init: @1728456 (descriptors) -> {"","","",""} => {"i","j","k","l"} +Operator Delete[] Statement + Destructor + erase: @1728456 (descriptors) -> {"i","j","k","l"} => {"","","",""} + Destructor + erase: @1728360 (descriptors) -> {"e","f","g","h"} => {"","","",""} + Operator Delete[] Overload + memory deallocation: for @1728352 +%% + %% +Operator Placement New + Constructor + init: @1375248 (descriptors) -> {"","","",""} => {"m","n","o","p"} +User call of Destructor + Destructor + erase: @1375248 (descriptors) -> {"m","n","o","p"} => {"","","",""} +%% + %% +Operator Placement New[] + Constructor + init: @1375248 (descriptors) -> {"","","",""} => {"q","r","s","t"} + Constructor + init: @1375344 (descriptors) -> {"","","",""} => {"u","v","w","x"} +User Call of Destructor + Destructor + erase: @1375248 (descriptors) -> {"q","r","s","t"} => {"","","",""} +User Call of Destructor + Destructor + erase: @1375344 (descriptors) -> {"u","v","w","x"} => {"","","",""} +%% +{{fbdoc item="section" value="See also"}} + - [[KeyPgOperator|Operator]] + - [[KeyPgConstructor|Constructor]] + - [[KeyPgDestructor|Destructor]] + +{{fbdoc item="back" value="CatPgProgrammer|Programmer's Guide"}} \ No newline at end of file diff --git a/doc/manual/cache/ProPgObjectLifetime.wakka b/doc/manual/cache/ProPgObjectLifetime.wakka new file mode 100644 index 0000000000..fd51ba79b5 --- /dev/null +++ b/doc/manual/cache/ProPgObjectLifetime.wakka @@ -0,0 +1,9 @@ +{{fbdoc item="title" value="Dynamic Object and Data Lifetime (IN PROGRESS...)"}}---- +**Lifetime** of **Dynamic Object** and its **Data**, created from declaration keyword for dynamic memory allocation. + +**Preamble:** + - The Lifetime of an object (and of its data) is the time period in which its instance name exists (and refers to valid data). But in absolute terms, the instance name of the object and its associated data can have two independent lifetimes (the Scope referring to the program part where the instance name is visible). + - The dynamic objects considered are the predefined pseudo-objects such as the variable-length strings/arrays, and the instances of complex UDT (with dynamic data allocated). Simple variables but dynamically allocated are also considered. + - The declaration keywords for dynamic memory allocation are: 'Allocate'/'Callocate'/'Reallocate', 'New', 'Imagecreate' (for deallocation: 'Deallocate', 'Delete', 'Imagedestroy'). + +For such objects and data dynamically allocated as defined above, the lifetime of the instance name of the object generally matches the surrounding scope (otherwise it can be greater than this one), but the lifetime of associated data may mismatch this one because the allocation/deallocation of associated data is triggered by the user himself. \ No newline at end of file diff --git a/doc/manual/cache/ProPgPassingArrays.wakka b/doc/manual/cache/ProPgPassingArrays.wakka new file mode 100644 index 0000000000..275ba9ccf1 --- /dev/null +++ b/doc/manual/cache/ProPgPassingArrays.wakka @@ -0,0 +1,101 @@ +{{fbdoc item="title" value="Passing Arrays to Procedures"}}---- +Declaring/defining array parameters and passing array arguments to procedures + +{{fbdoc item="section" value="Syntax for array symbol name"}} + As parameter in procedure declaration: + ##**( [ [[KeyPgAny|any]] [, [[KeyPgAny|any]]...] ] )** [[KeyPgAs|as]] [[DataType|datatype]]## + ##**array_name( [ [[KeyPgAny|any]] [, [[KeyPgAny|any]]...] ] )** [[KeyPgAs|as]] [[DataType|datatype]]## + As parameter in procedure definition: + ##**array_name( [ [[KeyPgAny|any]] [, [[KeyPgAny|any]]...] ] )** [[KeyPgAs|as]] [[DataType|datatype]]## + As argument in procedure call: + ##**array_name()**## + + Parentheses (even empty) are mandatory to specify that the parameter/argument is an array. + +{{fbdoc item="section" value="Usage of array symbol name"}} + When declaring procedure with array parameter: + ##[[KeyPgDeclare|declare]] { [[KeyPgSub|sub]] | [[KeyPgFunction|function]] } //proc_name// ... ( **( [ [[KeyPgAny|any]] [, [[KeyPgAny|any]]...] ] )** [[KeyPgAs|as]] [[DataType|datatype]] , ... ) [ ... ]## + ##[[KeyPgDeclare|declare]] { [[KeyPgSub|sub]] | [[KeyPgFunction|function]] } //proc_name// ... ( **array_parameter_name( [ [[KeyPgAny|any]] [, [[KeyPgAny|any]]...] ] )** [[KeyPgAs|as]] [[DataType|datatype]] , ... ) [ ... ]## + When defining procedure with array parameter: + ##{ [[KeyPgSub|sub]] | [[KeyPgFunction|function]] } //proc_name// ... ( **array_parameter_name( [ [[KeyPgAny|any]] [, [[KeyPgAny|any]]...] ] )** [[KeyPgAs|as]] [[DataType|datatype]] , ... ) [ ... ]## + When passing array argument to procedure: + ##//sub_name ( **array_argument_name()** , ... )//## + ##//sub_name **array_argument_name()** , ...//## + ##//funct_name ( **array_argument_name()** , ... )//## + ##//funct_name **array_argument_name()** , ...//## + ##//... funct_name ( **array_argument_name()** , ... ) [ ... ]//## + + **Note** (same rules as for any parameter/argument list)**:** + When declaring/defining a procedure, parentheses surrounding a non empty parameter list are required. + When calling a subroutine, parentheses surrounding an argument list (empty or non empty) are optional. + When calling a function as a subroutine (without using the return variable), the same rules as for subroutine apply. + When calling a function in an expression (which uses the return value), parentheses surrounding a non empty argument list are required. + But it is a common convention to always use parentheses (empty or non empty) after the procedure name, to signify a procedure call. + +{{fbdoc item="section" value="Description"}} + Array parameter can not have a ##[[KeyPgByval|byval]]## or ##[[KeyPgByref|byref]]## keyword before them, because arrays don't get passed the same way as normal parameters. While variables get passed by value or by reference, arrays get passed by descriptor (see below). In fact when an array is passed to a procedure, it is a reference to its descriptor which is passed. + All the elements of a passed array can be modified, and those changes are reflected at the calling level. Perhaps ##[[KeyPgByref|byref]]## should be allowed by similarity with variable-length string (which are also passed by descriptor). + + There is no direct possibility of passing an array by value. Declaring a passed array parameter ##[[KeyPgAs|as]] [[KeyPgConstQualifier|constant]]## only forbids any modification in the procedure body. A workaround would be to pass a user copy of the array. + + **Note:** + A function return can not be an array type variable. + A fixed-length ##[[KeyPgString|string]]## array can not be passed to a procedure. + A ##[[KeyPgZstring|zstring]]/[[KeyPgWstring|wstring]]## array can not be simply passed to a procedure because the zstring/wstring size is not passed (the ##//"as zstring/wstring * 1"//## type is taken by default by compiler in procedure body). It is a bug at the moment because compiler just fails silently while it badly computes in the procedure body the address of each array element (except the first obviously). + + **Array descriptor** (for information purposes only)**:** + For a fixed-length array, the descriptor is only used for passing the array to a procedure (otherwise the compiler does not use it because knowing the fixed characteristics of the array). + For a variable-length array, the descriptor is always used (the array descriptor is the only defining the array characteristics). + + The array descriptor has the following structure (each item is coded on an 'Any Ptr' or an 'Uinteger', except on an 'Integer' for lbound and ubound): + **""-""** pointer to the real or virtual element: @array(0, 0, ...) + **""-""** pointer to the first real element: @array(lbound1, lbound2, ...) + **""-""** "global" size in bytes: (ubound1 - lbound1 + 1) * (ubound2 - lbound2 + 1) * ... * (size of 1 element in bytes) + **""-""** size of one element in bytes + **""-""** number of dimensions + then for each dimension: + **""-""** number of elements: (ubound - lbound + 1) + **""-""** lbound + **""-""** ubound + +{{fbdoc item="section" value="Example"}} + + {{fbdoc item="filename" value="examples/manual/proguide/arrays/passing.bas"}}%%(freebasic) +Declare Sub splitString(ByVal As String, (Any) As String, ByVal As UByte = Asc(",")) + + +Dim As String s = "Programmer's Guide/Variables and Datatypes/Arrays/Passing Arrays to Procedures" +Dim As String array(Any) + +splitString(s, array(), Asc("/")) + +Print "STRING TO SPLIT:" +Print s +Print +Print "RESULT ARRAY FROM SPLITTING:" +For i As Integer = LBound(array) To UBound(array) + Print i, array(i) +Next i + +Sleep + + +Sub splitString(ByVal source As String, destination(Any) As String, ByVal delimitor As UByte) + Do + Dim As Integer position = InStr(1, source, Chr(delimitor)) + ReDim Preserve destination(UBound(destination) + 1) + If position = 0 Then + destination(UBound(destination)) = source + Exit Do + End If + destination(UBound(destination)) = Left(source, position - 1) + source = Mid(source, position + 1) + Loop +End Sub +%% +{{fbdoc item="section" value="See also"}} + - [[ProPgPassingArguments|Passing Arguments to Procedures]] + - [[ProPgCallingConventions|Calling Conventions]] + - [[ProPgReturnValue|Returning a Value]] + +{{fbdoc item="back" value="CatPgProgrammer|Programmer's Guide"}} \ No newline at end of file diff --git a/doc/manual/cache/ProPgRecursion.wakka b/doc/manual/cache/ProPgRecursion.wakka new file mode 100644 index 0000000000..a9a982ea0b --- /dev/null +++ b/doc/manual/cache/ProPgRecursion.wakka @@ -0,0 +1,302 @@ +{{fbdoc item="title" value="Recursion"}}---- +Recursive procedures (subroutines or functions) + +Iteration and recursion are two very useful ways to program, especially to perform a certain number of times a certain script, and thus allow optimization of the code. If iteration is relatively easy to understand, recursion is a concept not necessarily obvious at the beginning. +When speaking of a recursive procedure (subroutine or function), we refer to a syntactic characteristic: the procedure, in its own definition, refers to itself (it calls itself). +But when talking about recursive process, linear or tree, we are interested in the process flow, not in the syntax of the procedure's writing. +Thus, a procedure can have a recursive definition but correspond to an iterative process. + +Some treatments are naturally implemented as a recursive algorithm (although this is not always the most optimal solution). +The main problem of the recursive approach is that it consumes potentially a lot of space on the execution stack: from a certain level of "depth" of recursion, the space allocated for the execution stack of the thread is exhausted, and causes an error of type "stack overflow". +Repeatedly calling the same procedure can also make the execution slower, although this may make the code easier. +To increase the speed of execution, simple recursive algorithms can be recreated in little more complicated iterative algorithms using loops that execute much faster. + +What is the use of recursion if it increases the execution time and memory space compared to an iterative solution? +There are still cases where it is not possible to do otherwise, where iterative translation does not exist or, where it exists, is much heavier to implement (requiring for example a dynamic storage capacity to substitute for the execution stack). + +{{fbdoc item="section" value="Recursion beside iteration"}} + Iteration and recursion both repeatedly execute the instruction set: + - Iteration occurs when a loop executes repeatedly until the control condition becomes false. + - Recursion occurs when an instruction in a procedure calls the procedure itself repeatedly. + The main difference between iteration and recursion is that iteration is a process applied to a set of instructions to execute repeatedly, while recursion is a process always applied to a procedure. + + __Definition of iteration__ + Iteration is a process of repeatedly executing a set of instructions until the iteration condition becomes false. + The iteration block includes the initialization, the comparison, the execution of the instructions to be iterated and finally the update of the control variable. + Once the control variable is updated, it is compared again and the process is repeated until the condition in the iteration is false. + Iteration blocks are ##[[KeyPgFor|For]]## loop, ##[[KeyPgWhile|While]]## loop, ... + + The iteration block does not use the execution stack to store the variables at each cycle. Therefore, the execution of the iteration block is faster than the recursion block. In addition, iteration does not have the overhead of repeated procedure calls that also make its execution faster than a recursion. + The iteration is complete when the control condition becomes false. + + Simple example with a iterative function which returns the factorial of the integer: + {{fbdoc item="filename" value="examples/manual/proguide/recursion/iterativefactorial.bas"}}%%(freebasic) +'' The code body of the iterative function is defined by using the iterative definition of the factorial function: +'' Case (n = 0) : factorial(0) = 1 +'' Case (n > 0) : factorial(n) = (1) * ..... * (n - 2) * (n - 1) * (n) +'' The first line allows to determine the cumulative variable initialization: 'result = 1' +'' The second line allows to determine the statement syntax which accumulates: 'result = result * I' + +Function iterativeFactorial (Byval n As Integer) As Integer + Dim As Integer result = 1 '' variable initialization + For I As Integer = 1 To n '' iteration loop + result = result * I '' iterative accumulation + Next I + Return result +End Function + +Print iterativeFactorial(6) + +Sleep +%% + __Definition of recursion__ + FreeBASIC allows a procedure to call itself in its code. This means that the procedure definition has a procedure call to itself. The set of local variables and parameters used by the procedure are newly created each time the procedure is called and are stored at the top of the execution stack. But every time a procedure calls itself, it does not create a new copy of that procedure. The recursive procedure does not significantly reduce the size of the code and does not even improve the memory usage, but it does a little bit compared to iteration. + + To end recursion, a condition must be tested to force the return of the procedure without giving a recursive call to itself. The absence of a test of a condition in the definition of a recursive procedure would leave the procedure in infinite recursion once called. + + **Note:** When the parameters of a recursive procedure are passed by reference, take care to work with local variables when the code body needs to modify their values. + + Simple example with a recursive function which returns the factorial of the integer: + {{fbdoc item="filename" value="examples/manual/proguide/recursion/recursivefactorial.bas"}}%%(freebasic) +'' The code body of the recursive function is defined by using the recursive definition of the factorial function: +'' Case (n = 0) : factorial(0) = 1 +'' Case (n > 0) : factorial(n) = n * factorial(n-1) +'' The first line allows to determine the end condition: 'If (n = 0) Then Return 1' +'' The second line allows to determine the statement syntax which calls the function itself: 'Return n * factorial(n - 1)' + +Function recursiveFactorial (Byval n As Integer) As Integer + If (n = 0) Then '' end condition + Return 1 + Else '' recursion loop + Return n * recursiveFactorial(n - 1) '' recursive call + End If +End Function + +Print recursiveFactorial(6) + +Sleep +%% +{{fbdoc item="section" value="Recursion structure"}} + Different types of recursion structure can be found: + - Tail recursion. + - Non-tail but final recursion. + - Non-tail and non-final recursion. + - Mutual recursion. + - Nested recursion. + + + __Tail recursion__ + The recursive procedure is a tail recursive procedure if the only recursive call is at the end of the recursion and is therefore not followed by any other statement: + - for a recursive subroutine, the only recursive call is at the end of the recursion, + - for a recursive function, the only recursive call is at the end of the recursion and consists in taking into account the return of the function without any other additional operation on it. + A tail recursive procedure is easy to transform into an iterative procedure. + + Example with the simple "factorial" recursive function (already presented above): + - This function has a non-tail recursive form because even though the recursive call is at the end of function, this recursive call is not the last instruction of the function because one has to multiplied again by 'n' when 'recursiveFactorial(n - 1)' is got. + - This calculation is done when popping context from execution stack. + + + It is quite easy to transform this function so that the recursion is a tail recursion. + To achieve this, it is necessary to add a new parameter to the function: the 'result' parameter which will serve as accumulator: + {{fbdoc item="filename" value="examples/manual/proguide/recursion/tailrecursivefactorial.bas"}}%%(freebasic) +Function tailRecursiveFactorial (Byval n As Integer, Byval result As Integer = 1) As Integer + If (n = 0) Then '' end condition + Return result + Else '' recursion loop + Return tailRecursiveFactorial(n - 1, result * n) '' tail recursive call + End If +End Function + +Print tailRecursiveFactorial(6) + +Sleep + %%This time, the calculation is done when pushing context on execution stack. + + Similar transformation steps for the simple "reverse string" recursive function following: + {{fbdoc item="filename" value="examples/manual/proguide/recursion/recursivereverse.bas"}}%%(freebasic) +Function recursiveReverse (Byval s As String) As String + If (s = "") Then '' end condition + Return s + Else '' recursion loop + Return recursiveReverse(Mid(s, 2)) & Left(s, 1) '' recursive call + End If +End Function + +Print recursiveReverse("9876543210") + +Sleep +%% + {{fbdoc item="filename" value="examples/manual/proguide/recursion/tailrecursivereverse.bas"}}%%(freebasic) +Function tailRecursiveReverse (Byval s As String, Byval cumul As String = "") As String + If (s = "") Then '' end condition + Return cumul + Else '' recursion loop + Return tailRecursiveReverse(Mid(s, 2), Left(s, 1) & cumul) '' tail recursive call + End If +End Function + +Print tailRecursiveReverse("9876543210") + +Sleep + %%**Note:** As the "&" operator (string concatenation) is not a symmetric operator ('(a & b) <> (b & a)', while '(x * y) = (y * x)' like previously), the two operand order must to be reversed when pushing context on execution stack instead of before when popping context from execution stack. + + __Non-tail but final recursion__ + A non-tail recursive procedure is final when the recursive call(s) is(are) placed at the end of executed code (no executable instruction line after and between for several recursive calls). + + First example, computation of the combination coefficients nCp (binomial coefficients calculation) and display of the Pascal's triangle: + {{fbdoc item="filename" value="examples/manual/proguide/recursion/recursivecombination.bas"}}%%(freebasic) +Function recursiveCombination (Byval n As Uinteger, Byval p As Uinteger) As Longint + If p = 0 Or p = n then + Return 1 + Else + Return recursiveCombination(n - 1, p) + recursiveCombination(n - 1, p - 1) + End If +End Function + +Dim As Uinteger n = 10 +For I As Uinteger = 0 To n + For J As Uinteger = 0 To I + Locate , 6 * J + 3 * (n - I) + 3 + Print recursiveCombination(I, J); + Next J + Print +Next I + +Sleep +%% + Second example, recursive drawing of circles: + {{fbdoc item="filename" value="examples/manual/proguide/recursion/recursivecircle.bas"}}%%(freebasic) +Sub recursiveCircle (Byval x As Integer, Byval y As Integer, Byval r As Integer) + Circle (x, y), r + If r > 16 Then + recursiveCircle(x + r / 2, y, r / 2) + recursiveCircle(x - r / 2, y, r / 2) + recursiveCircle(x, y + r / 2, r / 2) + recursiveCircle(x, y - r / 2, r / 2) + End If +End Sub + +Screen 12 + +Locate 2, 2 +recursiveCircle(160, 160, 150) + +Sleep +%% + Third example, quick sort algorithm: + {{fbdoc item="filename" value="examples/manual/proguide/recursion/recursivequicksort.bas"}}%%(freebasic) +Dim shared As Ubyte t(99) + +Sub recursiveQuicksort (Byval L As Integer, Byval R As Integer) + Dim As Integer pivot = L, I = L, J = R + Do + If t(I) >= t(J) then + Swap t(I), t(J) + pivot = L + R - pivot + End If + If pivot = L then + J = J - 1 + Else + I = I + 1 + End If + Loop Until I = J + If L < I - 1 Then + recursiveQuicksort(L, I - 1) + End If + If R > J + 1 Then + recursiveQuicksort(J + 1, R) + End If +End Sub + +Randomize +For I As Integer = Lbound(t) To Ubound(t) + t(i) = Int(Rnd * 256) +Next I + +Print "raw memory:" +For K As Integer = Lbound(t) To Ubound(t) + Print Using "####"; t(K); +Next K +Print + +recursiveQuicksort(Lbound(t), Ubound(t)) + +Print "sorted memory:" +For K As Integer = Lbound(t) To Ubound(t) + Print Using "####"; t(K); +Next K +Print + +Sleep +%% + __Non-tail and non-final recursion__ + A non-tail recursive procedure is also not final when the recursive call(s) is(are) not all placed at the end of executed code (an executable instruction line at least after or between for several recursive calls). + + Example, tower of Hanoi algorithm: + {{fbdoc item="filename" value="examples/manual/proguide/recursion/recursivehanoi.bas"}}%%(freebasic) +'' For this example, the two recursive calls are at the end of executed code block but separated by an instruction line and there is an order constraint. + +Sub recursiveHanoi (Byval n As Integer, Byval departure As String, Byval middle As String, Byval arrival As String) + If n > 0 Then + recursiveHanoi(n - 1, departure, arrival, middle) + Print " move one disk from " & departure & " to " & arrival + recursiveHanoi(n -1 , middle, departure, arrival) + End If +End Sub + +recursiveHanoi(3, "A", "B", "C") + +Sleep +%% + __Mutual recursion__ + Two functions are said to be mutually recursive if the first calls the second, and in turn the second calls the first. + + Example using mutual recursive, 'even()' and 'odd()' recursive functions: + {{fbdoc item="filename" value="examples/manual/proguide/recursion/recursiveisevenodd.bas"}}%%(freebasic) +Declare Function recursiveIsEven(Byval n As Integer) As Boolean +Declare Function recursiveIsOdd(Byval n As Integer) As Boolean + +Function recursiveIsEven(Byval n As Integer) As Boolean + If n = 0 Then + Return True + Else + Return recursiveIsOdd(n - 1) + End If +End Function + +Function recursiveIsOdd(Byval n As Integer) As Boolean + If n = 0 Then + Return False + Else + Return recursiveIsEven(n - 1) + End If +End Function + +Print recursiveIsEven(16), recursiveIsOdd(16) +Print recursiveIsEven(17), recursiveIsOdd(17) + +Sleep +%% + __Nested recursion__ + A recursive function is said nested if an argument passed to the function refers to the function itself. + + Example using nested recursive function, 'Ackermann()' recursive function: + {{fbdoc item="filename" value="examples/manual/proguide/recursion/recursiveackermann.bas"}}%%(freebasic) +Function recursiveAckermann (Byval m As Integer, Byval n As Integer) As Integer + If m = 0 Then + Return n + 1 + Else + If n = 0 Then + Return recursiveAckermann(m - 1, 1) + Else + Return recursiveAckermann(m - 1, recursiveAckermann(m, n - 1)) + End If + End If +End Function + +Print recursiveAckermann(3, 0), recursiveAckermann(3, 1), recursiveAckermann(3, 2), recursiveAckermann(3, 3), recursiveAckermann(3, 4) + +Sleep +%% + +{{fbdoc item="back" value="CatPgProgrammer|Programmer's Guide"}} \ No newline at end of file diff --git a/doc/manual/cache/ProPgTypeIterators.wakka b/doc/manual/cache/ProPgTypeIterators.wakka new file mode 100644 index 0000000000..2a9837bdef --- /dev/null +++ b/doc/manual/cache/ProPgTypeIterators.wakka @@ -0,0 +1,308 @@ +{{fbdoc item="title" value="Iterators"}}---- +The overload Operators **For**, **Next**, and **Step**, allowing to construct User-Defined Types **Iterators** (instead of only intrinsic scalar types iterators) for a For...Next loop + +{{fbdoc item="section" value="Syntax (declaration)"}} + { [[KeyPgType|Type]] | [[KeyPgClass|Class]] | [[KeyPgUnion|Union]] } //typename// + ' ##[[KeyPgFornext|For...Next]]## statement with implicit step (1st version of operators) + [[KeyPgDeclare|declare]] **Operator** [[KeyPgOpFor|For]] ( ) + [[KeyPgDeclare|declare]] **Operator** [[KeyPgOpNext|Next]] ( [ [[KeyPgByref|byref]] | [[KeyPgByval|byval]] ] //cond// [[KeyPgAs|as]] //typename// ) [[KeyPgAs|as]] [[KeyPgInteger|Integer]] + [[KeyPgDeclare|declare]] **Operator** [[KeyPgOpStep|Step]] ( ) + ' ##[[KeyPgFornext|For...Next]]## statement with explicit step (2nd version of operators) + [[KeyPgDeclare|declare]] **Operator** [[KeyPgOpFor|For]] ( [ [[KeyPgByref|byref]] | [[KeyPgByval|byval]] ] //stp// [[KeyPgAs|as]] //typename// ) + [[KeyPgDeclare|declare]] **Operator** [[KeyPgOpNext|Next]] ( [ [[KeyPgByref|byref]] | [[KeyPgByval|byval]] ] //cond// [[KeyPgAs|as]] //typename//, [ [[KeyPgByref|byref]] | [[KeyPgByval|byval]] ] //stp// [[KeyPgAs|as]] //typename// ) [[KeyPgAs|as]] [[KeyPgInteger|Integer]] + [[KeyPgDeclare|declare]] **Operator** [[KeyPgOpStep|Step]] ( [ [[KeyPgByref|byref]] | [[KeyPgByval|byval]] ] //stp// [[KeyPgAs|as]] //typename// ) + End { [[KeyPgType|Type]] | [[KeyPgClass|Class]] | [[KeyPgUnion|Union]] } + +{{fbdoc item="section" value="Usage"}} + [[KeyPgFornext|For]] //iterator// [ As //typename// ] = //start_value// To //end_value// [ [[KeyPgFornext|Step]] //step_value// ] + [// ...statements... //] + [[KeyPgFornext|Next]] + + The first version of operators is used if no ##//step_value//## is given in the ##[[KeyPgFornext|For...Next]]## statement. + If a ##//step_value//## is given, the second version is used and a step object (initialized with ##//step-value//##) is passed through the ##//stp//## parameter: + **""-""** to ##[[KeyPgOpFor|Operator For]]## because eventual additional initialization may use it, + **""-""** to ##[[KeyPgOpNext|Operator Next]]## because testing for iterating end may depend on it, + **""-""** to ##[[KeyPgOpStep|Operator Step]]## to increment the iterator object. + Both versions of the operators can coexist (thanks to member overloading) in the same user-defined type (to be able to both use and not use the explicit increment in ##[[KeyPgFornext|For...Next]]## statements of the user code). + +{{fbdoc item="section" value="Parameters"}} + ##//typename//## + name of the ##[[KeyPgType|Type]]##, ##[[KeyPgClass|Class]]##, or ##[[KeyPgUnion|Union]]## + ##//stp//##, ##//step_value//## + a ##//typename//## object used as an incremental value + ##//iterator//## + a ##//typename//## object used as an iterator + ##//cond//##, ##//end_value//## + a ##//typename//## object used as a loop-terminating value + ##//start_value//## + a ##//typename//## object used to copy construct or assign to the iterator initially + +{{fbdoc item="section" value="Description"}} + ##[[KeyPgOpFor|Operator For]]##, ##[[KeyPgOpNext|Operator Next]]## and ##[[KeyPgOpStep|Operator Step]]## can be overloaded in user-defined type definitions to allow objects of that type to be used as iterators and step values in ##[[KeyPgFornext|For...Next]]## loops (instead of the pre-defined for intrinsic scalar types). + + As all non-static member procedures, the 3 operators have passed a hidden ##[[KeyPgThis|this]]## parameter that allows to access by reference to the iterator object (initialized to the ##//start_value//## argument value from the ##[[KeyPgFornext|For...Next]]## statement). + The ##//cond//## parameter of the ##[[KeyPgOpNext|Operator Next]]## allows to access the ##//end_value//## argument value from the ##[[KeyPgFornext|For...Next]]## statement. + If a ##//step_value//## is given (as argument) in the ##[[KeyPgFornext|For...Next]]## statement, the ##//stp//## parameter allows to access this value in the 3 operators. + + **Note:** If no ##//step_value//## is given in the ##[[KeyPgFornext|For...Next]]## statement (implicit step), the user-defined type must have a default constructor (implicit or explicit) or a conversion constructor. It is a bug at the moment because if the user defines a default constructor, the compiler does not even use it when initializing the ##[[KeyPgFornext|For...Next]]## loop! + + __Operator For__ + ##[[KeyPgOpFor|Operator For]]## is called once immediately after copy constructing or assigning to the iterator object (with the ##//start_value//##), constructing the end object (with the ##//end_value//##), and constructing the step object (with ##//step_value//## if defined in the ##[[KeyPgFornext|For...Next]]## statement). + ##[[KeyPgOpFor|Operator For]]## allows to perform any additional initialization needed in preparation for the loop. + + __Operator Next__ + ##[[KeyPgOpNext|Operator Next]]## is called every time the iterator object needs to be checked against the end value. This happens immediately after the call to the ##[[KeyPgOpFor|Operator For]]##, and then immediately after any calls to the ##[[KeyPgOpStep|Operator Step]]##. + ##[[KeyPgOpNext|Operator Next]]## should return zero (0) if the loop should be terminated, or non-zero if the loop should continue iterating. + The first time ##[[KeyPgOpNext|Operator Next]]## is called, no statements in the ##[[KeyPgFornext|For...Next]]## body have been executed yet. + ##[[KeyPgOpNext|Operator Next]]## also allows to perform some processing before the execution of all statements in the ##[[KeyPgFornext|For...Next]]## body. + + __Operator Step__ + ##[[KeyPgOpStep|Operator Step]]## is called to increment the iterator object immediately after all statements in the ##[[KeyPgFornext|For...Next]]## body are executed. + +{{fbdoc item="section" value="Algorithm"}} + ##[[KeyPgFornext|For...Next]]## loop algorithm around the 3 overload operators: + %% +' FOR...NEXT loop +' V +' | +' constructing/assigning iterator object +' (This = start_value from For...Next statement) +' | +' constructing end object +' (cond = end_value from For...Next statement) +' | +' if step_value is defined >---------------------. +' else : +' v v +' : constructing step object +' : (stp = step_value from For...Next statement) +' : : +' :<----------------------------------' +' | +' calling Operator For +' | +' .----------------------->| +' | | +' | calling Operator Next +' | (if end-condition verified: =0 returned) >-------------. +' | (else: <>0 returned) | +' | v | +' | | | +' | executing For...Next body | +' | | | +' | calling Operator Step | +' | | | +' '------------------------' | +' | +' V +%% +{{fbdoc item="section" value="Example"}} + Type for iterating through screen resolutions, with implicit step-value: + {{fbdoc item="filename" value="examples/manual/proguide/iterators/resolution.bas"}}%%(freebasic) +Type screenResolution + ' user interface + Declare Constructor (ByVal colorBit As Long) + Declare Property colorDepth () As Long + Declare Property screenWidth () As Long + Declare Property screenHeigth () As Long + ' overload iteration operators when Step is not defined in For...Next statement + Declare Operator For () + Declare Operator Next (ByRef iterateCondition As screenResolution) As Integer + Declare Operator Step () + ' internal variables + Dim As Long colorBit, resolutionWH +End Type + +Constructor screenResolution (Byval colorBit As Long) + This.colorBit = colorBit +End Constructor + +Property screenResolution.colorDepth () As Long + Return This.colorBit +End Property + +Property screenResolution.screenWidth () As Long + Return Hiword(This.resolutionWH) +End Property + +Property screenResolution.screenHeigth () As Long + Return Loword(This.resolutionWH) +End Property + +Operator screenResolution.For () + This.resolutionWH = ScreenList(This.colorBit) +End Operator + +Operator screenResolution.Next (ByRef iterateCondition As screenResolution) As Integer + While This.resolutionWH = 0 + If This.colorBit < iterateCondition.colorBit Then + This.colorBit += 1 + This.resolutionWH = ScreenList(This.colorBit) + Else + Exit While + End If + Wend + Return (This.resolutionWH <> iterateCondition.resolutionWH) +End Operator + +Operator screenResolution.Step () + This.resolutionWH = ScreenList() +End Operator + + +Print "Screen resolutions supported within [1 bpp , 64 bpp]:" +For iterator As screenResolution = screenResolution(1) To screenResolution(64) + Print " " & iterator.colorDepth & " bpp ", + Print ":" & iterator.screenWidth & "x" & iterator.screenHeigth +Next iterator +Print "End of supported screen resolutions" + +Sleep + %%Output example: + %% +Screen resolutions supported within [1 bpp , 64 bpp]: + 24 bpp :320x200 + 24 bpp :320x240 + 24 bpp :400x300 + 24 bpp :512x384 + 24 bpp :640x400 + 24 bpp :640x480 + 24 bpp :800x600 + 24 bpp :1024x768 + 24 bpp :1152x864 + 24 bpp :1280x600 + 24 bpp :1280x720 + 24 bpp :1280x768 + 24 bpp :1280x800 + 24 bpp :1280x960 + 24 bpp :1280x1024 + 24 bpp :1360x768 + 24 bpp :1366x768 + 24 bpp :1400x1050 + 24 bpp :1440x900 + 24 bpp :1600x900 + 24 bpp :1680x1050 + 24 bpp :1920x1080 + 32 bpp :320x200 + 32 bpp :320x240 + 32 bpp :400x300 + 32 bpp :512x384 + 32 bpp :640x400 + 32 bpp :640x480 + 32 bpp :800x600 + 32 bpp :1024x768 + 32 bpp :1152x864 + 32 bpp :1280x600 + 32 bpp :1280x720 + 32 bpp :1280x768 + 32 bpp :1280x800 + 32 bpp :1280x960 + 32 bpp :1280x1024 + 32 bpp :1360x768 + 32 bpp :1366x768 + 32 bpp :1400x1050 + 32 bpp :1440x900 + 32 bpp :1600x900 + 32 bpp :1680x1050 + 32 bpp :1920x1080 +End of supported screen resolutions +%% + Type for iterating through fractions, with explicit step-value used in the 3 operators: + (improved example compared to the one of ##[[KeyPgOpStep|Operator Step]]## page) + {{fbdoc item="filename" value="examples/manual/proguide/iterators/fraction.bas"}}%%(freebasic) +Type fraction + ' user interface + Declare Constructor (ByVal n As Integer, ByVal d As Integer) + Declare Operator Cast () As String + ' overload iteration operators when Step is defined in For...Next statement + Declare Operator For (ByRef iterateStep As fraction) + Declare Operator Next (ByRef iterateCondition As fraction, ByRef iterateStep As fraction) As Integer + Declare Operator Step (ByRef step_var As fraction) + ' internal variables and cast operator + As Integer num, den + Declare Operator Cast () As Double +End Type + +Constructor fraction (Byval n As Integer, Byval d As Integer) + this.num = n + this.den = d +End Constructor + +Operator fraction.Cast () As String + ' search for the highest common factor (a) between numerator and denominator + Dim As Integer a = Abs(This.num), b = Abs(This.den) + If a <> 0 Then + While a <> b + If a > b Then + a -= b + Else + b -= a + End If + Wend + Else + a = 1 + End If + ' reduce the fraction + Return num \ a & "/" & den \ a +End Operator + +Operator fraction.Cast () As Double + Return This.num / This.den +End Operator + +Operator fraction.For (Byref iterateStep As fraction) + ' search for the least common multiple (a) between the two denominators + Dim As Integer a = Abs(This.den), b = Abs(iterateStep.den), c = a, d = b + While a <> b + If a > b Then + b += d + Else + a += c + End If + Wend + ' align at the same denominator the 2 fractions + This.num *= a \ This.den + This.den = a + iterateStep.num *= a \ iterateStep.den + iterateStep.den = a +End Operator + +Operator fraction.Next (Byref iterateCondition As fraction, Byref iterateStep As fraction) As Integer + If iterateStep.num < 0 Or iterateStep.den < 0 Then + Return This >= iterateCondition + Else + Return This <= iterateCondition + End If +End Operator + +Operator fraction.Step (Byref iterateStep As fraction) + This.num += iterateStep.num +End Operator + + +Print "iteration from 1/8 to 1/2 by step of 1/12:" +For iterator As fraction = fraction(1, 8) To fraction(1, 2) Step fraction(1, 12) + Print " " & iterator; +Next +Print +Print +Print "iteration from 7/10 to -8/5 by step of -8/15:" +For iterator As fraction = fraction(7, 10) To fraction(-8, 5) Step fraction(-8, 15) + Print " " & iterator; +Next +Print + +Sleep + %%Output: + %% +iteration from 1/8 to 1/2 by step of 1/12: + 1/8 5/24 7/24 3/8 11/24 + +iteration from 7/10 to -8/5 by step of -8/15: + 7/10 1/6 -11/30 -9/10 -43/30 +%% +{{fbdoc item="section" value="See also"}} + - [[KeyPgFornext|For...Next]] + - [[KeyPgOperator|Operator]] + +{{fbdoc item="back" value="CatPgProgrammer|Programmer's Guide"}} \ No newline at end of file diff --git a/doc/manual/cache/ProPgUDTs.wakka b/doc/manual/cache/ProPgUDTs.wakka index 140a1233ac..d14ed1f7b7 100644 --- a/doc/manual/cache/ProPgUDTs.wakka +++ b/doc/manual/cache/ProPgUDTs.wakka @@ -2,7 +2,7 @@ Custom types. {{fbdoc item="section" value="Overview"}} - //User-Defined Types// are special kinds of [[ProPgVariables|variables]] which can be created by the programmer. A User-Defined Type (UDT) is really just a container that contains a bunch of other variables, like an [[ProPgArrays|array]], but unlike arrays UDTs can hold //different// variable types (whereas arrays always hold many variables of the //same// type). In fact, UDTs can even have [[ProPgProcedures|procedures]] inside of them! + //User-Defined Types// are special kinds of [[ProPgVariables|variables]] which can be created by the programmer. A User-Defined Type (UDT) is really just a container that contains a bunch of other variables, like an [[ProPgArrays|array]], but unlike arrays, UDTs can hold //different// variable types (whereas arrays always hold many variables of the //same// type). In fact, UDTs can even have [[ProPgProcedures|procedures]] inside of them! {{fbdoc item="section" value="Members"}} The different variables and/or procedures stored inside a UDT are called "members", or more generally, items. Members can be variables of just about any type, including numerical types, strings, [[ProPgPointers|pointers]], [[KeyPgEnum|enums]], and even arrays. Variables are created in UDTs much the same way variables are created normally, except that the Dim keyword is optional. UDT members are accessed via the [[KeyPgOpMemberAccess|. operator]], so for example if you created a variable called someVar in a UDT you would access it with the name of the UDT variable followed by ".someVar". Here is an example: @@ -24,7 +24,7 @@ Print myUDT.someVar Notice that the [[KeyPgType|Type...End Type]] does not actually create a variable of that type, it only defines what variables of that type contain. You must create a variable of that type to actually use it! {{fbdoc item="section" value="UDT Pointers"}} - UDT Pointers are, as the name implies, pointers to UDTs. They are created like regular pointers, but there is a special way to use them. To access the member of a UDT pointed to by a pointer, you use the [[KeyPgOpPtrMemberAccess|-> operator]]. For example, if myUDTPtr is a pointer to a UDT which has a member someVar, you would access the member as myUDTPtr->someVar, which is a much cleaner shorthand for the equally valid *(myUDTPtr).someVar. + UDT Pointers are, as the name implies, pointers to UDTs. They are created like regular pointers, but there is a special way to use them. To access the member of a UDT pointed to by a pointer, you use the [[KeyPgOpPtrMemberAccess|-> operator]]. For example, if myUDTPtr is a pointer to a UDT which has a member someVar, you would access the member as myUDTPtr->someVar, which is a much cleaner shorthand for the equally valid (*myUDTPtr).someVar. {{fbdoc item="filename" value="examples/manual/proguide/udt/ptr-access.bas"}}%%(freebasic) Type rect diff --git a/doc/manual/cache/ProPgVariableLifetime.wakka b/doc/manual/cache/ProPgVariableLifetime.wakka new file mode 100644 index 0000000000..f678588053 --- /dev/null +++ b/doc/manual/cache/ProPgVariableLifetime.wakka @@ -0,0 +1,47 @@ +{{fbdoc item="title" value="Simple Variable Lifetime vs Scope (IN PROGRESS...)"}}---- +**Lifetime** of **Simple Variable**, created from declaration keyword for static memory allocation, relative to its **Scopes**. + +**Preamble:** + - The Lifetime of a variable is the time period in which the variable has valid memory (the Scope referring to the program part where its name is visible). The value of a variable may change during its lifetime, but it retains some consistent value. + - The simple variables considered are the predefined variables including the raw pointers, and the fixed-length strings/arrays, but excluding the variable-length strings/arrays. Instances of simple UDT (without any dynamic data allocated) are also considered. + - The declaration keywords for static memory allocation are: 'Dim', 'Static', 'Var'. + +For such variables allocated in static way as defined above, the lifetime generally matches the surrounding scope, otherwise it can be greater than this one. + +{{fbdoc item="section" value="Declaration syntax for a lifetime matching the surrounding scope"}} + For such variables declared anywhere, as follows (or similar syntax): + ##(1) [[KeyPgDim|Dim]] [[[KeyPgByrefVariables|Byref]]] ++Shared++ [[KeyPgAs|As]] [[DataType|datatype]] [[[KeyPgPtr|Ptr]]] //variablename// ...## + ##or## + ##(2) [[KeyPgVar|Var]] [[[KeyPgByrefVariables|Byref]]] ++Shared++ //variablename// = //expression//## + ##(equivalent to: '[[KeyPgDim|Dim]] [[[KeyPgByrefVariables|Byref]]] ++Shared++ [[KeyPgAs|As]] [[KeyPgTypeof|Typeof]]((//expression//)) = //expression//')## + or + ##(3) {[[KeyPgDim|Dim]]|[[KeyPgStatic|Static]]} [[[KeyPgByrefVariables|Byref]]] [[KeyPgShared|Shared]] [[KeyPgAs|As]] [[DataType|datatype]] [[[KeyPgPtr|Ptr]]] //variablename// ...## + ##or## + ##(4) [[KeyPgVar|Var]] [[[KeyPgByrefVariables|Byref]]] [[KeyPgShared|Shared]] //variablename// = //expression//## + ##(equivalent to: '[[KeyPgDim|Dim]] [[[KeyPgByrefVariables|Byref]]] [[KeyPgShared|Shared]] [[KeyPgAs|As]] [[KeyPgTypeof|Typeof]]((//expression//)) = //expression//')## + they always have a lifetime matching their surrounding scope (global scope, or scope block, or compound statement block, or procedure scope). + + With (1) or (2) syntax ('Shared' not used), these local variables are always allocated on the program stack at the time of their declarations, and are automatically deallocated when going out their scopes. + With (3) or (4) syntax ('Shared' used), these global variables are always allocated in the .BSS or .DATA section of the executable (their scopes and lifetimes begin at program creation and end with program termination). + +{{fbdoc item="section" value="Declaration syntax for a lifetime greater than (otherwise equal to) the surrounding scope"}} + For such variables declared anywhere, as follows (or similar syntax): + ##[[KeyPgStatic|Static]] [[[KeyPgByrefVariables|Byref]]] ++Shared++ [[KeyPgAs|As]] [[DataType|datatype]] [[[KeyPgPtr|Ptr]]] //variablename// ...## + they always have a lifetime equal to the program duration, so greater than their surrounding scope if there are declared in any local scope block (matching their surrounding scope if there are declared in the global scope). + + These static variables are always allocated in the .BSS or .DATA section of the executable (their lifetimes begin at program creation and end with program termination). + + Interest of declaring such static variables in a compound instruction block or in a procedure scope: + **""-""** As for 'Dim', the 'Static' keyword is used in a compound statement block or in a procedure scope to declare variables whose scope stops at the end of the compound statement block or the procedure. + **""-""** However, unlike 'Dim', the lifetime differs because the variables declared with the 'Static' keyword retain their value between the successive loops of the compound instruction block or the successive calls to the procedure. + **""-""** In summary, a declared static variable has a local scope, but its lifetime is comparable to that of a global scope variable. + **""-""** So, static variables with the same name can be declared in several different compound statement blocks and in different procedure scopes. Each of these variables therefore remains independent and retains its own value in its own local scope. + +{{fbdoc item="section" value="Example"}} + + +{{fbdoc item="section" value="See also"}} + - [[ProPgVariableScope|Variable Scope]] + - [[ProPgObjectLifetime|Dynamic Object and Data Lifetime]] + +{{fbdoc item="back" value="CatPgProgrammer|Programmer's Guide"}} \ No newline at end of file diff --git a/doc/manual/cache/ProPgVariableScope.wakka b/doc/manual/cache/ProPgVariableScope.wakka index 6ffb3e671f..b8388bb0cb 100644 --- a/doc/manual/cache/ProPgVariableScope.wakka +++ b/doc/manual/cache/ProPgVariableScope.wakka @@ -6,17 +6,17 @@ A variable's scope refers to its visibility in a program. A variable is not visi In FreeBASIC, there are 4 categories of scope: **//local//**, **//shared//**, **//common//** and **//common shared//**. Each of these scopes has different visibility rules, which are detailed below. {{fbdoc item="section" value="Local Scope"}} - Variables declared in the local scope are visible only in the most local instance of the IF, FOR, SCOPE, function, or module block in which they are declared. + Variables declared in the local scope are visible only in the most local instance of the IF, SELECT, WITH, FOR, WHILE, DO, SCOPE, procedure, or module block in which they are declared. - ##[[KeyPgSub|Sub]]##, ##[[KeyPgFunction|Function]]##, the main body, and each compound statement implicitly define a new local scope block. - - Explicitly declared variables using ##[[KeyPgDim|Dim]]## or ##[[KeyPgRedim|Redim]]## take the scope of the local most block in which they are declared. + - Explicitly declared variables using ##[[KeyPgDim|Dim]]## or ##[[KeyPgRedim|Redim]]## or ##[[KeyPgStatic|Static]]## take the scope of the local most block in which they are declared. - Implicit variables take the scope of the the local most ##[[KeyPgScope|Scope...End Scope]]## block in which they are first used, otherwise take the scope of the ##[[KeyPgSub|Sub]]##, ##[[KeyPgFunction|Function]]##, or main body in which they are used. - In the local scope, there is no visibility between module-level code and function level code. Furthermore, variables dimensioned within a block decision or loop statement will only be visible within the block in which they are dimensioned. Variables declared in the local scope of a module are not visible in any of the functions within that module. Similarly, local variables declared inside functions are not visible in the module-level code, nor any other function within the module. + In the local scope, there is no visibility between module-level code and procedure level code. Furthermore, variables dimensioned within a block decision or loop statement will only be visible within the block in which they are dimensioned. Variables declared in the local scope of a module are not visible in any of the procedures within that module. Similarly, local variables declared inside procedures are not visible in the module-level code, nor any other procedure within the module. Variables declared inside ##[[KeyPgScope|Scope]]## blocks may only be declared of local scope, and are not visible outside the block. ##[[KeyPgScope|Scope]]## blocks, however, inherit the surrounding scope, so local variables declared outside the ##[[KeyPgScope|Scope]]## block will be visible inside (//see example program//). - You can declare a variable to be of local scope explicitly by using the ##[[KeyPgDim|Dim]]## statement, or implicitly by simply introducing the variable (//see [[ProPgImplicitdeclarations|Implicit Declarations]]//). The example program ##**local.bas**## demonstrates visibility rules for the local scope. + You can declare a variable to be of local scope explicitly by using the ##[[KeyPgDim|Dim]]## statement, or implicitly (for only //[[CompilerOptlang|-lang qb]]// and //[[CompilerOptlang|-lang fblite]]// dialects) by simply introducing the variable (//see [[ProPgImplicitdeclarations|Implicit Declarations]]//). The example program ##**local.bas**## demonstrates visibility rules for the local scope. ##**local.bas**## {{fbdoc item="filename" value="examples/manual/proguide/varscope/local.bas"}}%%(freebasic) @@ -62,13 +62,13 @@ End 0 %% {{fbdoc item="section" value="Shared Scope"}} - Variables declared in the shared scope of a module are visible to both the module and all functions of that module. + Variables declared in the shared scope of a module are visible to both the module and all procedures of that module. - Unlike the local scope, the shared scope makes module-level variables visible to functions of that module. In other words, the module //shares// its declarations with its functions. + Unlike the local scope, the shared scope makes module-level variables visible to procedures of that module. In other words, the module //shares// its declarations with its procedures. - Variables can only be declared to be of shared scope at the module-level. Ie., only modules can share variables. Neither functions nor ##[[KeyPgScope|Scope]]## blocks can declare variables in the shared scope, thus variables declared there can only be local to that function or block. + Variables can only be declared to be of shared scope at the module-level. Ie., only modules can share variables. Neither procedures nor ##[[KeyPgScope|Scope]]## blocks can declare variables in the shared scope, thus variables declared there can only be local to that procedure or block. - You can declare a variable to be of shared scope by using the DIM statement with the ##[[KeyPgShared|Shared]]## keyword. The example program ##**shared_scope.bas**## demonstrates visibility rules for the shared scope. + You can declare a variable to be of shared scope by using the DIM (or REDIM or STATIC) statement with the ##[[KeyPgShared|Shared]]## keyword. The example program ##**shared_scope.bas**## demonstrates visibility rules for the shared scope. ##**shared.bas**## {{fbdoc item="filename" value="examples/manual/proguide/varscope/shared.bas"}}%%(freebasic) @@ -123,7 +123,6 @@ Print "m2 = "; m2 ' m2 = 2 as set in module2 Print_Values %% - ##**module2.bas**## {{fbdoc item="filename" value="examples/manual/proguide/varscope/module2.bas"}}%%(freebasic) Common m1 As Integer @@ -137,11 +136,10 @@ print "m2 = "; m2 ' m2 = 2 Sub Print_Values() print "Module2.Print_Values" - print "m1 = "; m1 ' Implicit variable = 0 - print "m2 = "; m2 ' Implicit variable = 0 + print "m1 = "; m1 ' Implicit variable = 0, because '-lang qb' use + print "m2 = "; m2 ' Implicit variable = 0, because '-lang qb' use End Sub %% - //**##Output:##**// %% Module2 @@ -156,7 +154,7 @@ End Sub %% {{fbdoc item="section" value="Common Shared Scope"}} - Variables declared in the common shared scope are visible to all modules and all functions of those modules. + Variables declared in the common shared scope are visible to all modules and all procedures of those modules. Variables declared with ##[[KeyPgCommon|Common]]## are visible to other modules with a matching ##[[KeyPgCommon|Common]]## variable declaration. The variable name declared must match from between modules. Within a module the ##[[KeyPgShared|Shared]]## declaration modifier gives the variable module scope and makes the variable visible to all subs and functions. @@ -178,7 +176,6 @@ print "m2 = "; m2 '' m2 = 2 as set in module2 Print_Values %% - ##**module4.bas**## {{fbdoc item="filename" value="examples/manual/proguide/varscope/module4.bas"}}%%(freebasic) Common Shared m1 As Integer @@ -196,7 +193,6 @@ Sub Print_Values() print "m2 = "; m2 '' m2 = 2 End Sub %% - //**##Output:##**// %% Module4 @@ -222,4 +218,4 @@ End Sub - [[ProPgImplicitdeclarations|Implicit Declarations]] {{fbdoc item="back" value="CatPgProgrammer|Programmer's Guide"}} - + \ No newline at end of file diff --git a/doc/manual/cache/TblVarTypes.wakka b/doc/manual/cache/TblVarTypes.wakka index 2012a2854d..51c1fa8643 100644 --- a/doc/manual/cache/TblVarTypes.wakka +++ b/doc/manual/cache/TblVarTypes.wakka @@ -17,7 +17,7 @@ Standard variable types and limits. {{fbdoc item="section" value="Arrays"}} -~~{{table columns="5" cellpadding="2" cells="Platform ; Maximum Subscript Range ; Maximum Elements per Dimension ; Minimum/Maximum Dimensions ; Maximum Size (in bytes) ; 32bit ; [*][-2147483648, +2147483647] ; [*]+2147483647 ; 1/9 ; [*]+2147483647 ; 64bit ; [*][-9223372036854775808, +9223372036854775807] ; [*]+9223372036854775807 ; 1/9 ; [*]+9223372036854775807"}} +~~{{table columns="5" cellpadding="2" cells="Platform ; Maximum Subscript Range ; Maximum Elements per Dimension ; Minimum/Maximum Dimensions ; Maximum Size (in bytes) ; 32bit ; [*][-2147483648, +2147483647] ; [*]+2147483647 ; 1/8 ; [*]+2147483647 ; 64bit ; [*][-9223372036854775808, +9223372036854775807] ; [*]+9223372036854775807 ; 1/8 ; [*]+9223372036854775807"}} ~&[*] //All runtime library array procedures take and produce ##[[KeyPgInteger|Integer]]## values for subscripts and indexes. The actual limits will vary (smaller) with the number of dimensions, element size, storage location and/or platform.// diff --git a/examples/manual/check/FBWikiKeywordTemplate_1.bas b/examples/manual/check/FBWikiKeywordTemplate_1.bas deleted file mode 100644 index 25120d8427..0000000000 --- a/examples/manual/check/FBWikiKeywordTemplate_1.bas +++ /dev/null @@ -1,12 +0,0 @@ -'' examples/manual/check/FBWikiKeywordTemplate_1.bas -'' -'' NOTICE: This file is part of the FreeBASIC Compiler package and can't -'' be included in other distributions without authorization. -'' -'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=FBWikiKeywordTemplate -'' -------- - -'' sample code -'' sample code -'' sample code -'' sample code diff --git a/examples/manual/datatype/pointer.bas b/examples/manual/datatype/pointer.bas index 93af20b9d4..d56ccf3a67 100644 --- a/examples/manual/datatype/pointer.bas +++ b/examples/manual/datatype/pointer.bas @@ -3,7 +3,7 @@ '' NOTICE: This file is part of the FreeBASIC Compiler package and can't '' be included in other distributions without authorization. '' -'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgPointer +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgPtr '' -------- Dim p As ZString Pointer diff --git a/examples/manual/debug/assert.bas b/examples/manual/debug/assert.bas index 57b63a3be8..1c23e510ee 100644 --- a/examples/manual/debug/assert.bas +++ b/examples/manual/debug/assert.bas @@ -14,4 +14,4 @@ End Sub foo -'' If -g is used this code stops with: test.bas(3): assertion failed at FOO: a=1 +'' If -g or -eassert is used, this code stops with: test.bas(3): assertion failed at FOO: a=1 diff --git a/examples/manual/proguide/arrays/passing.bas b/examples/manual/proguide/arrays/passing.bas new file mode 100644 index 0000000000..ea3465cba4 --- /dev/null +++ b/examples/manual/proguide/arrays/passing.bas @@ -0,0 +1,39 @@ +'' examples/manual/proguide/arrays/passing.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgPassingArrays +'' -------- + +Declare Sub splitString(ByVal As String, (Any) As String, ByVal As UByte = Asc(",")) + + +Dim As String s = "Programmer's Guide/Variables and Datatypes/Arrays/Passing Arrays to Procedures" +Dim As String array(Any) + +splitString(s, array(), Asc("/")) + +Print "STRING TO SPLIT:" +Print s +Print +Print "RESULT ARRAY FROM SPLITTING:" +For i As Integer = LBound(array) To UBound(array) + Print i, array(i) +Next i + +Sleep + + +Sub splitString(ByVal source As String, destination(Any) As String, ByVal delimitor As UByte) + Do + Dim As Integer position = InStr(1, source, Chr(delimitor)) + ReDim Preserve destination(UBound(destination) + 1) + If position = 0 Then + destination(UBound(destination)) = source + Exit Do + End If + destination(UBound(destination)) = Left(source, position - 1) + source = Mid(source, position + 1) + Loop +End Sub diff --git a/examples/manual/proguide/iterators/fraction.bas b/examples/manual/proguide/iterators/fraction.bas new file mode 100644 index 0000000000..2633a152c1 --- /dev/null +++ b/examples/manual/proguide/iterators/fraction.bas @@ -0,0 +1,92 @@ +'' examples/manual/proguide/iterators/fraction.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgTypeIterators +'' -------- + +Type fraction + ' user interface + Declare Constructor (ByVal n As Integer, ByVal d As Integer) + Declare Operator Cast () As String + ' overload iteration operators when Step is defined in For...Next statement + Declare Operator For (ByRef iterateStep As fraction) + Declare Operator Next (ByRef iterateCondition As fraction, ByRef iterateStep As fraction) As Integer + Declare Operator Step (ByRef step_var As fraction) + ' internal variables and cast operator + As Integer num, den + Declare Operator Cast () As Double +End Type + +Constructor fraction (ByVal n As Integer, ByVal d As Integer) + this.num = n + this.den = d +End Constructor + +Operator fraction.Cast () As String + ' search for the highest common factor (a) between numerator and denominator + Dim As Integer a = Abs(This.num), b = Abs(This.den) + If a <> 0 Then + While a <> b + If a > b Then + a -= b + Else + b -= a + End If + Wend + Else + a = 1 + End If + ' reduce the fraction + Return num \ a & "/" & den \ a +End Operator + +Operator fraction.Cast () As Double + Return This.num / This.den +End Operator + +Operator fraction.For (ByRef iterateStep As fraction) + ' search for the least common multiple (a) between the two denominators + Dim As Integer a = Abs(This.den), b = Abs(iterateStep.den), c = a, d = b + While a <> b + If a > b Then + b += d + Else + a += c + End If + Wend + ' align at the same denominator the 2 fractions + This.num *= a \ This.den + This.den = a + iterateStep.num *= a \ iterateStep.den + iterateStep.den = a +End Operator + +Operator fraction.Next (ByRef iterateCondition As fraction, ByRef iterateStep As fraction) As Integer + If iterateStep.num < 0 Or iterateStep.den < 0 Then + Return This >= iterateCondition + Else + Return This <= iterateCondition + End If +End Operator + +Operator fraction.Step (ByRef iterateStep As fraction) + This.num += iterateStep.num +End Operator + + +Print "iteration from 1/8 to 1/2 by step of 1/12:" +For iterator As fraction = fraction(1, 8) To fraction(1, 2) Step fraction(1, 12) + Print " " & iterator; +Next +Print +Print +Print "iteration from 7/10 to -8/5 by step of -8/15:" +For iterator As fraction = fraction(7, 10) To fraction(-8, 5) Step fraction(-8, 15) + Print " " & iterator; +Next +Print + +Sleep + diff --git a/examples/manual/proguide/iterators/resolution.bas b/examples/manual/proguide/iterators/resolution.bas new file mode 100644 index 0000000000..7b842464ad --- /dev/null +++ b/examples/manual/proguide/iterators/resolution.bas @@ -0,0 +1,68 @@ +'' examples/manual/proguide/iterators/resolution.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgTypeIterators +'' -------- + +Type screenResolution + ' user interface + Declare Constructor (ByVal colorBit As Long) + Declare Property colorDepth () As Long + Declare Property screenWidth () As Long + Declare Property screenHeigth () As Long + ' overload iteration operators when Step is not defined in For...Next statement + Declare Operator For () + Declare Operator Next (ByRef iterateCondition As screenResolution) As Integer + Declare Operator Step () + ' internal variables + Dim As Long colorBit, resolutionWH +End Type + +Constructor screenResolution (ByVal colorBit As Long) + This.colorBit = colorBit +End Constructor + +Property screenResolution.colorDepth () As Long + Return This.colorBit +End Property + +Property screenResolution.screenWidth () As Long + Return HiWord(This.resolutionWH) +End Property + +Property screenResolution.screenHeigth () As Long + Return LoWord(This.resolutionWH) +End Property + +Operator screenResolution.For () + This.resolutionWH = ScreenList(This.colorBit) +End Operator + +Operator screenResolution.Next (ByRef iterateCondition As screenResolution) As Integer + While This.resolutionWH = 0 + If This.colorBit < iterateCondition.colorBit Then + This.colorBit += 1 + This.resolutionWH = ScreenList(This.colorBit) + Else + Exit While + End If + Wend + Return (This.resolutionWH <> iterateCondition.resolutionWH) +End Operator + +Operator screenResolution.Step () + This.resolutionWH = ScreenList() +End Operator + + +Print "Screen resolutions supported within [1 bpp , 64 bpp]:" +For iterator As screenResolution = screenResolution(1) To screenResolution(64) + Print " " & iterator.colorDepth & " bpp ", + Print ":" & iterator.screenWidth & "x" & iterator.screenHeigth +Next iterator +Print "End of supported screen resolutions" + +Sleep + diff --git a/examples/manual/proguide/namespaces/access.bas b/examples/manual/proguide/namespaces/access.bas new file mode 100644 index 0000000000..f9136b25a6 --- /dev/null +++ b/examples/manual/proguide/namespaces/access.bas @@ -0,0 +1,17 @@ +'' examples/manual/proguide/namespaces/access.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgNamespaces +'' -------- + +Dim As Integer i ' Declare i in the global scope + +Namespace A + Dim As Integer i = 2 ' Declare i in Namespace A + Dim As Integer j = 3 ' Declare j in Namespace A +End Namespace + +i = 1 ' Use i from global scope (.i) +A.i = 4 ' Use i from Namespace A (A.i) diff --git a/examples/manual/proguide/namespaces/conflict.bas b/examples/manual/proguide/namespaces/conflict.bas new file mode 100644 index 0000000000..a3d8cbfd19 --- /dev/null +++ b/examples/manual/proguide/namespaces/conflict.bas @@ -0,0 +1,25 @@ +'' examples/manual/proguide/namespaces/conflict.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgNamespaces +'' -------- + +Namespace A + Dim As Integer i ' Declare A.i + Dim As Integer j ' Declare A.j +End Namespace + +Namespace B + Dim As Integer i ' Declare B.i + Dim As Integer j ' Declare B.j + Using A ' A.i/j and B.i/j are in conflict, but no error is given +End Namespace + +Dim As Integer j ' Declare also j the global scope + +Using B +'i = 1 ' error: Ambiguous symbol access, explicit scope resolution required (between B.i and A.i) +B.i = 1 ' ambiguity resolution solved by using full name +j = 2 ' ambiguity (between .j, B.j, A.j) solved by compiler, by choosing override .j in the global scope diff --git a/examples/manual/proguide/namespaces/extension1.bas b/examples/manual/proguide/namespaces/extension1.bas new file mode 100644 index 0000000000..36efe68a3c --- /dev/null +++ b/examples/manual/proguide/namespaces/extension1.bas @@ -0,0 +1,19 @@ +'' examples/manual/proguide/namespaces/extension1.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgNamespaces +'' -------- + +Namespace A ' Declaration of Namespace A + Dim As Integer i +End Namespace + +Namespace B ' Declaration of Namespace B + Dim As Integer i +End Namespace + +Namespace A ' Extension of Namespace A + Dim As Integer j +End Namespace diff --git a/examples/manual/proguide/namespaces/extension2.bas b/examples/manual/proguide/namespaces/extension2.bas new file mode 100644 index 0000000000..4ff8031aa9 --- /dev/null +++ b/examples/manual/proguide/namespaces/extension2.bas @@ -0,0 +1,20 @@ +'' examples/manual/proguide/namespaces/extension2.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgNamespaces +'' -------- + +Namespace A + Dim As Integer i +End Namespace + +Using A + +Namespace A + Dim As Integer j +End Namespace + +i = 0 ' Initialize A.i +j = 0 ' Initialize A.j diff --git a/examples/manual/proguide/namespaces/externdef.bas b/examples/manual/proguide/namespaces/externdef.bas new file mode 100644 index 0000000000..b914e5314b --- /dev/null +++ b/examples/manual/proguide/namespaces/externdef.bas @@ -0,0 +1,15 @@ +'' examples/manual/proguide/namespaces/externdef.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgNamespaces +'' -------- + +Namespace A + Declare Function f () As Integer ' Declaration of f() in Namespace A (A.f()) +End Namespace + +Function A.f () As Integer ' Definition of f() from Namespace A (A.f()) + Return 0 +End Function diff --git a/examples/manual/proguide/namespaces/nested.bas b/examples/manual/proguide/namespaces/nested.bas new file mode 100644 index 0000000000..3b2bf767d3 --- /dev/null +++ b/examples/manual/proguide/namespaces/nested.bas @@ -0,0 +1,14 @@ +'' examples/manual/proguide/namespaces/nested.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgNamespaces +'' -------- + +Namespace A + Dim As Integer i ' (A.i) + Namespace B + Dim As Integer j ' (A.B.j) + End Namespace +End Namespace diff --git a/examples/manual/proguide/namespaces/using.bas b/examples/manual/proguide/namespaces/using.bas new file mode 100644 index 0000000000..1cbcc59e9e --- /dev/null +++ b/examples/manual/proguide/namespaces/using.bas @@ -0,0 +1,16 @@ +'' examples/manual/proguide/namespaces/using.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgNamespaces +'' -------- + +Namespace A + Dim As Integer i ' Declaration of A.i + Dim As Integer j ' Declaration of A.j +End Namespace + +Using A ' Namespace A identifiers are also used +i = 1 ' Equivalent to A.i +j = 1 ' Equivalent to A.j diff --git a/examples/manual/proguide/newdelete/operators.bas b/examples/manual/proguide/newdelete/operators.bas new file mode 100644 index 0000000000..923fb327d4 --- /dev/null +++ b/examples/manual/proguide/newdelete/operators.bas @@ -0,0 +1,115 @@ +'' examples/manual/proguide/newdelete/operators.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgNewDelete +'' -------- + +Declare Sub printArray (ByRef label As String = "", array() As String) + + +Type UDT + Declare Constructor () + Declare Destructor () + Declare Operator New (ByVal size As UInteger) As Any Ptr ' Operator New Overload + Declare Operator New[] (ByVal size As UInteger) As Any Ptr ' Operator New[] Overload + Declare Operator Delete (ByVal buf As Any Ptr) ' Operator Delete Overload + Declare Operator Delete[] (ByVal buf As Any Ptr) ' Operator Delete[] Overload + Dim As String array (1 To 4) +End Type + +Constructor UDT () + Static As Integer n + Print " Constructor" + printArray(" init: @" & @This & " (descriptors) -> ", This.array()) + For i As Integer = LBound(This.array) To UBound(This.array) + This.array(i) = Chr(Asc("a") + n + i - LBound(This.array)) + Next i + printArray(" => ", This.array()) + Print + n += UBound(This.array)- LBound(This.array) + 1 +End Constructor + +Destructor UDT () + Print " Destructor" + printArray(" erase: @" & @This & " (descriptors) -> ", This.array()) + Erase This.array + printArray(" => ", This.array()) + Print +End Destructor + +Operator UDT.New (ByVal size As UInteger) As Any Ptr + Print " Operator New Overload" + Dim As Any Ptr p = Allocate(size) ' Memory allocation (with passed size) + Print " memory allocation: "; + Print size & " Bytes from @" & p + Return p ' Returning memory pointer +End Operator + +Operator UDT.New[] (ByVal size As UInteger) As Any Ptr + Print " Operator New[] Overload" + Dim As Any Ptr p = Allocate(size) ' Memory allocation (with passed size) + Print " memory allocation: "; + Print size & " Bytes from @" & p + Return p ' Returning memory pointer +End Operator + +Operator UDT.Delete (ByVal buf As Any Ptr) + Print " Operator Delete Overload" + Deallocate(buf) ' Memory deallocation (with passed pointer) + Print " memory deallocation: "; + Print "for @" & buf +End Operator + +Operator UDT.Delete[] (ByVal buf As Any Ptr) + Print " Operator Delete[] Overload" + Deallocate(buf) ' Memory deallocation (with passed pointer) + Print " memory deallocation: "; + Print "for @" & buf +End Operator + + +Print "Operator New Expression" +Dim As UDT Ptr pu1 = New UDT ' Operator New Expression +Print "Operator Delete Statement" +Delete pu1 ' Operator Delete Statement +Sleep + +Print +Print "Operator New[] Expression" +Dim As UDT Ptr pu2 = New UDT[2] ' Operator New[] Expression +Print "Operator Delete[] Statement" +Delete[] pu2 ' Operator Delete[] Statement +Sleep + +Dim As Byte buffer(1 To 256) +Dim As Any Ptr p = @buffer(1) + +Print +Print "Operator Placement New" +Dim As UDT Ptr pu3 = New(p) UDT ' Operator Placement New +Print "User call of Destructor" +pu3->Destructor() ' User Call of Destructor +Sleep + +Print +Print "Operator Placement New[]" +Dim As UDT Ptr pu4 = New(p) UDT[2] ' Operator Placement New[] +For i As Integer = 0 To 1 + Print "User Call of Destructor" + pu4[i].Destructor() ' User Call of Destructor +Next i +Sleep + + +Sub printArray (ByRef label As String = "", array() As String) + Print label & "{"; + For i As Integer = LBound(array) To UBound(array) + Print """" & array(i) & """"; + If i < UBound(array) Then + Print ","; + End If + Next I + Print "}"; +End Sub diff --git a/examples/manual/proguide/recursion/iterativefactorial.bas b/examples/manual/proguide/recursion/iterativefactorial.bas new file mode 100644 index 0000000000..4a2bf62d22 --- /dev/null +++ b/examples/manual/proguide/recursion/iterativefactorial.bas @@ -0,0 +1,25 @@ +'' examples/manual/proguide/recursion/iterativefactorial.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgRecursion +'' -------- + +'' The code body of the iterative function is defined by using the iterative definition of the factorial function: +'' Case (n = 0) : factorial(0) = 1 +'' Case (n > 0) : factorial(n) = (1) * ..... * (n - 2) * (n - 1) * (n) +'' The first line allows to determine the cumulative variable initialization: 'result = 1' +'' The second line allows to determine the statement syntax which accumulates: 'result = result * I' + +Function iterativeFactorial (ByVal n As Integer) As Integer + Dim As Integer result = 1 '' variable initialization + For I As Integer = 1 To n '' iteration loop + result = result * I '' iterative accumulation + Next I + Return result +End Function + +Print iterativeFactorial(6) + +Sleep diff --git a/examples/manual/proguide/recursion/recursiveackermann.bas b/examples/manual/proguide/recursion/recursiveackermann.bas new file mode 100644 index 0000000000..b06d87329d --- /dev/null +++ b/examples/manual/proguide/recursion/recursiveackermann.bas @@ -0,0 +1,23 @@ +'' examples/manual/proguide/recursion/recursiveackermann.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgRecursion +'' -------- + +Function recursiveAckermann (ByVal m As Integer, ByVal n As Integer) As Integer + If m = 0 Then + Return n + 1 + Else + If n = 0 Then + Return recursiveAckermann(m - 1, 1) + Else + Return recursiveAckermann(m - 1, recursiveAckermann(m, n - 1)) + End If + End If +End Function + +Print recursiveAckermann(3, 0), recursiveAckermann(3, 1), recursiveAckermann(3, 2), recursiveAckermann(3, 3), recursiveAckermann(3, 4) + +Sleep diff --git a/examples/manual/proguide/recursion/recursivecircle.bas b/examples/manual/proguide/recursion/recursivecircle.bas new file mode 100644 index 0000000000..4be0e03edc --- /dev/null +++ b/examples/manual/proguide/recursion/recursivecircle.bas @@ -0,0 +1,24 @@ +'' examples/manual/proguide/recursion/recursivecircle.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgRecursion +'' -------- + +Sub recursiveCircle (ByVal x As Integer, ByVal y As Integer, ByVal r As Integer) + Circle (x, y), r + If r > 16 Then + recursiveCircle(x + r / 2, y, r / 2) + recursiveCircle(x - r / 2, y, r / 2) + recursiveCircle(x, y + r / 2, r / 2) + recursiveCircle(x, y - r / 2, r / 2) + End If +End Sub + +Screen 12 + +Locate 2, 2 +recursiveCircle(160, 160, 150) + +Sleep diff --git a/examples/manual/proguide/recursion/recursivecombination.bas b/examples/manual/proguide/recursion/recursivecombination.bas new file mode 100644 index 0000000000..770f99952c --- /dev/null +++ b/examples/manual/proguide/recursion/recursivecombination.bas @@ -0,0 +1,26 @@ +'' examples/manual/proguide/recursion/recursivecombination.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgRecursion +'' -------- + +Function recursiveCombination (ByVal n As UInteger, ByVal p As UInteger) As LongInt + If p = 0 Or p = n Then + Return 1 + Else + Return recursiveCombination(n - 1, p) + recursiveCombination(n - 1, p - 1) + End If +End Function + +Dim As UInteger n = 10 +For I As UInteger = 0 To n + For J As UInteger = 0 To I + Locate , 6 * J + 3 * (n - I) + 3 + Print recursiveCombination(I, J); + Next J + Print +Next I + +Sleep diff --git a/examples/manual/proguide/recursion/recursivefactorial.bas b/examples/manual/proguide/recursion/recursivefactorial.bas new file mode 100644 index 0000000000..f586be4d42 --- /dev/null +++ b/examples/manual/proguide/recursion/recursivefactorial.bas @@ -0,0 +1,25 @@ +'' examples/manual/proguide/recursion/recursivefactorial.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgRecursion +'' -------- + +'' The code body of the recursive function is defined by using the recursive definition of the factorial function: +'' Case (n = 0) : factorial(0) = 1 +'' Case (n > 0) : factorial(n) = n * factorial(n-1) +'' The first line allows to determine the end condition: 'If (n = 0) Then Return 1' +'' The second line allows to determine the statement syntax which calls the function itself: 'Return n * factorial(n - 1)' + +Function recursiveFactorial (ByVal n As Integer) As Integer + If (n = 0) Then '' end condition + Return 1 + Else '' recursion loop + Return n * recursiveFactorial(n - 1) '' recursive call + End If +End Function + +Print recursiveFactorial(6) + +Sleep diff --git a/examples/manual/proguide/recursion/recursivehanoi.bas b/examples/manual/proguide/recursion/recursivehanoi.bas new file mode 100644 index 0000000000..cfea42148a --- /dev/null +++ b/examples/manual/proguide/recursion/recursivehanoi.bas @@ -0,0 +1,21 @@ +'' examples/manual/proguide/recursion/recursivehanoi.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgRecursion +'' -------- + +'' For this example, the two recursive calls are at the end of executed code block but separated by an instruction line and there is an order constraint. + +Sub recursiveHanoi (ByVal n As Integer, ByVal departure As String, ByVal middle As String, ByVal arrival As String) + If n > 0 Then + recursiveHanoi(n - 1, departure, arrival, middle) + Print " move one disk from " & departure & " to " & arrival + recursiveHanoi(n -1 , middle, departure, arrival) + End If +End Sub + +recursiveHanoi(3, "A", "B", "C") + +Sleep diff --git a/examples/manual/proguide/recursion/recursiveisevenodd.bas b/examples/manual/proguide/recursion/recursiveisevenodd.bas new file mode 100644 index 0000000000..1ef002eb8f --- /dev/null +++ b/examples/manual/proguide/recursion/recursiveisevenodd.bas @@ -0,0 +1,31 @@ +'' examples/manual/proguide/recursion/recursiveisevenodd.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgRecursion +'' -------- + +Declare Function recursiveIsEven(ByVal n As Integer) As Boolean +Declare Function recursiveIsOdd(ByVal n As Integer) As Boolean + +Function recursiveIsEven(ByVal n As Integer) As Boolean + If n = 0 Then + Return True + Else + Return recursiveIsOdd(n - 1) + End If +End Function + +Function recursiveIsOdd(ByVal n As Integer) As Boolean + If n = 0 Then + Return False + Else + Return recursiveIsEven(n - 1) + End If +End Function + +Print recursiveIsEven(16), recursiveIsOdd(16) +Print recursiveIsEven(17), recursiveIsOdd(17) + +Sleep diff --git a/examples/manual/proguide/recursion/recursivequicksort.bas b/examples/manual/proguide/recursion/recursivequicksort.bas new file mode 100644 index 0000000000..9b2331f649 --- /dev/null +++ b/examples/manual/proguide/recursion/recursivequicksort.bas @@ -0,0 +1,51 @@ +'' examples/manual/proguide/recursion/recursivequicksort.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgRecursion +'' -------- + +Dim Shared As UByte t(99) + +Sub recursiveQuicksort (ByVal L As Integer, ByVal R As Integer) + Dim As Integer pivot = L, I = L, J = R + Do + If t(I) >= t(J) Then + Swap t(I), t(J) + pivot = L + R - pivot + End If + If pivot = L Then + J = J - 1 + Else + I = I + 1 + End If + Loop Until I = J + If L < I - 1 Then + recursiveQuicksort(L, I - 1) + End If + If R > J + 1 Then + recursiveQuicksort(J + 1, R) + End If +End Sub + +Randomize +For I As Integer = LBound(t) To UBound(t) + t(i) = Int(Rnd * 256) +Next I + +Print "raw memory:" +For K As Integer = LBound(t) To UBound(t) + Print Using "####"; t(K); +Next K +Print + +recursiveQuicksort(LBound(t), UBound(t)) + +Print "sorted memory:" +For K As Integer = LBound(t) To UBound(t) + Print Using "####"; t(K); +Next K +Print + +Sleep diff --git a/examples/manual/proguide/recursion/recursivereverse.bas b/examples/manual/proguide/recursion/recursivereverse.bas new file mode 100644 index 0000000000..788f4b1219 --- /dev/null +++ b/examples/manual/proguide/recursion/recursivereverse.bas @@ -0,0 +1,19 @@ +'' examples/manual/proguide/recursion/recursivereverse.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgRecursion +'' -------- + +Function recursiveReverse (ByVal s As String) As String + If (s = "") Then '' end condition + Return s + Else '' recursion loop + Return recursiveReverse(Mid(s, 2)) & Left(s, 1) '' recursive call + End If +End Function + +Print recursiveReverse("9876543210") + +Sleep diff --git a/examples/manual/proguide/recursion/tailrecursivefactorial.bas b/examples/manual/proguide/recursion/tailrecursivefactorial.bas new file mode 100644 index 0000000000..60c0652661 --- /dev/null +++ b/examples/manual/proguide/recursion/tailrecursivefactorial.bas @@ -0,0 +1,20 @@ +'' examples/manual/proguide/recursion/tailrecursivefactorial.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgRecursion +'' -------- + +Function tailRecursiveFactorial (ByVal n As Integer, ByVal result As Integer = 1) As Integer + If (n = 0) Then '' end condition + Return result + Else '' recursion loop + Return tailRecursiveFactorial(n - 1, result * n) '' tail recursive call + End If +End Function + +Print tailRecursiveFactorial(6) + +Sleep + diff --git a/examples/manual/proguide/recursion/tailrecursivereverse.bas b/examples/manual/proguide/recursion/tailrecursivereverse.bas new file mode 100644 index 0000000000..19d5f4e9f3 --- /dev/null +++ b/examples/manual/proguide/recursion/tailrecursivereverse.bas @@ -0,0 +1,20 @@ +'' examples/manual/proguide/recursion/tailrecursivereverse.bas +'' +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't +'' be included in other distributions without authorization. +'' +'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgRecursion +'' -------- + +Function tailRecursiveReverse (ByVal s As String, ByVal cumul As String = "") As String + If (s = "") Then '' end condition + Return cumul + Else '' recursion loop + Return tailRecursiveReverse(Mid(s, 2), Left(s, 1) & cumul) '' tail recursive call + End If +End Function + +Print tailRecursiveReverse("9876543210") + +Sleep + diff --git a/examples/manual/proguide/varscope/module2.bas b/examples/manual/proguide/varscope/module2.bas index 5026e5f92c..aeffba2426 100644 --- a/examples/manual/proguide/varscope/module2.bas +++ b/examples/manual/proguide/varscope/module2.bas @@ -17,6 +17,6 @@ Print "m2 = "; m2 ' m2 = 2 Sub Print_Values() Print "Module2.Print_Values" - Print "m1 = "; m1 ' Implicit variable = 0 - Print "m2 = "; m2 ' Implicit variable = 0 + Print "m1 = "; m1 ' Implicit variable = 0, because '-lang qb' use + Print "m2 = "; m2 ' Implicit variable = 0, because '-lang qb' use End Sub diff --git a/examples/manual/udt/extendszstring2.bas b/examples/manual/udt/extendszstring2.bas index dd94e9519a..6e13c0d145 100644 --- a/examples/manual/udt/extendszstring2.bas +++ b/examples/manual/udt/extendszstring2.bas @@ -47,7 +47,7 @@ End Destructor Operator Len (ByRef v As vZstring) As Integer Return Len(Type(v)) '' found nothing better than this ('vZstring.l' being private) -End Operator +End Operator '' (or: 'Return Len(Str(v))') Dim As vZstring v = "FreeBASIC" Print "'" & v & "'", Len(v) @@ -72,6 +72,6 @@ v[0] = Asc("-") Print "'" & v & "'", Len(v) 'Print "'" & Right(v, 5) & "'" '' 'Right' does not yet support types with 'Extends Zstring' -Print "'" & Right(Str(v), 5) & "'" '' workaround +Print "'" & Right(Str(v), 5) & "'" '' workaround (or: 'Right(Type(v), 5)') Sleep diff --git a/examples/manual/udt/operator2.bas b/examples/manual/udt/operator2.bas deleted file mode 100644 index 0ab3c4a57f..0000000000 --- a/examples/manual/udt/operator2.bas +++ /dev/null @@ -1,52 +0,0 @@ -'' examples/manual/udt/operator2.bas -'' -'' NOTICE: This file is part of the FreeBASIC Compiler package and can't -'' be included in other distributions without authorization. -'' -'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgOperator -'' -------- - -'' operator2.bas - -Const ALIGN = 256 - -Type UDT - Dim As Byte a(0 To 10 * 1024 * 1024 - 1) '' 10 megabyte fixed array - Declare Operator New (ByVal size As UInteger) As Any Ptr - Declare Operator Delete (ByVal buffer As Any Ptr) - Declare Constructor () - Declare Destructor () -End Type - -Operator UDT.New (ByVal size As UInteger) As Any Ptr - Print " Overloaded New operator, with parameter size = &h" & Hex(size) - Dim pOrig As Any Ptr = CAllocate(ALIGN-1 + SizeOf(UDT Ptr) + size) - Dim pMin As Any Ptr = pOrig + SizeOf(UDT Ptr) - Dim p As Any Ptr = pMin + ALIGN-1 - (CUInt(pMin + ALIGN-1) Mod ALIGN) - Cast(Any Ptr Ptr, p)[-1] = pOrig - Operator = p - Print " real pointer = &h" & Hex(pOrig), "return pointer = &h" & Hex(p) -End Operator - -Operator UDT.Delete (ByVal buffer As Any Ptr) - Print " Overloaded Delete operator, with parameter buffer = &h" & Hex(buffer) - Dim pOrig As Any Ptr = Cast(Any Ptr Ptr, buffer)[-1] - Deallocate(pOrig) - Print " real pointer = &h" & Hex(pOrig) -End Operator - -Constructor UDT () - Print " Constructor, @This = &h" & Hex(@This) -End Constructor - -Destructor UDT () - Print " Destructor, @This = &h" & Hex(@This) -End Destructor - -Print "'Dim As UDT Ptr p = New UDT'" -Dim As UDT Ptr p = New UDT - -Print " p = &h" & Hex(p) - -Print "'Delete p'" -Delete p