$CPP directive
Purpose: $CPP directive attempts C++ compliance in the translated code. Translated code is output to a file named with a .cpp extension. This directive is equivalent to using the BCX command line -c flag.
Example:
$CPP ' Turn on C++ features and use .cpp filename extension TestSub(1) TestSub(1, 2) TestSub(1, 2, 3) SUB TestSub OPTIONAL(a, b = 0, c = 0) PRINT IF a > 0 THEN PRINT a; IF b > 0 THEN PRINT b; IF c > 0 THEN PRINT c PRINT END SUB
Result:
1 1 2 1 2 3
$CPPHDR directive
When the $CPPHDR directive is used, with the $CPP directive, the BCX translator automatically adds the following code to the .cpp file translation produced by BCX.
// Additional lines may be needed #if defined(__cplusplus) #include <iostream> #include <fstream> #include <sstream> #include <iomanip> typedef std::string stdstr; #endif
To add other Standard C++ Library header files to the BCX code to be translated use the directive
#include <Filename>
$NOIO directive
Purpose:The $NOIO directive disables the inclusion of the <iostream> C++ header file.
By default, when the $CPPHDR directive is used, the BCX translation includes the <iostream> C++ header file. You can disable the inclusion by adding the line $NOIO to your BCX program source code, placing it immediately after the $CPPHDR directive.
The C++ Tutorial for BCX Users
With the permission of the original author Eric Brasseur, the following is an abridged BCX version of Brasseur's "The C++ tutorial for C users".
Chapter 3. Console input and output streams
Input from the keyboard and output to the screen can be performed through std::cin >> and std::cout <<.
Example C03.bas:
$CPP $NOMAIN #INCLUDE <iostream> FUNCTION MAIN() DIM age% DIM name$ std::cout << "This is a sample program." << std::endl std::cout << std::endl ' Just a line feed (end of line) std::cout << "Type your age : " std::cin >> age% std::cout << "Type your name: " std::cin >> name$ std::cout << std::endl std::cout << "Hello " << name$ << " you're " << age% << " years old." << std::endl std::cout << std::endl << std::endl << "Bye!" << std::endl END FUNCTION
Result:
This is a sample program. Type your age : 24 Type your name: BCX Hello BCX you're 24 years old. Bye!
Chapter 7. Global variables
A global variable can be accessed even if another variable with the same name has been declared inside the function.
Example C07.bas:
$CPP $NOMAIN #INCLUDE <iostream> DIM a# = 128 FUNCTION MAIN () DIM a# = 256 std::cout << "Local a: " << a# << std::endl std::cout << "Global a: " << ::a# << std::endl END FUNCTION
Result:
Local a: 256 Global a: 128
Chapter 8. Reference
It is possible to make one variable be another.
Example C08_01.bas:
$CPP $NOMAIN #INCLUDE <iostream> FUNCTION MAIN () DIM a# = 3.1415927 DIM AS DOUBLE &b = a ' b is a# b = 89 std::cout << "a# contains: " << a# << std::endl END FUNCTION
Result:
a# contains: 89
If you are used to pointers and absolutely want to know what happens, simply think
DOUBLE &b = a
is translated to
DOUBLE *b = &a
and all subsequent b are replaced by *b.
The value of reference b cannot be changed after its declaration. For example you cannot write, a few lines further,
&b = c
expecting that b is now c. It won't work. Everything is said on the declaration line of b. Reference b and variable a are married on that line and nothing will separate them.
References can be used to allow a function to modify a calling variable
Example C08_02.bas:
$CPP $NOMAIN #INCLUDE <iostream> SUB Change (r AS DOUBLE &, s AS DOUBLE) r = 100 s = 200 END SUB FUNCTION MAIN () RAW AS DOUBLE k, m k = 3 m = 4 CALL Change(k, m) std::cout << k << ", " << m << std::endl END FUNCTION
Result:
100, 4
A reference can be used to let a function return a variable.
Example C08_03.bas:
$CPP $NOMAIN #INCLUDE <iostream> FUNCTION biggest (r AS DOUBLE &, s AS DOUBLE &) AS DOUBLE & IF r > s THEN FUNCTION = r FUNCTION = s END FUNCTION FUNCTION MAIN () RAW AS DOUBLE k = 3 RAW AS DOUBLE m = 7 std::cout << "k: " << k << std::endl std::cout << "m: " << m << std::endl std::cout << std::endl biggest (k, m) = 10 std::cout << "k: " << k << std::endl std::cout << "m: " << m << std::endl std::cout << std::endl biggest (k, m) ++ std::cout << "k: " << k << std::endl std::cout << "m: " << m << std::endl std::cout << std::endl END FUNCTION
Result:
k: 3 m: 7 k: 3 m: 10 k: 3 m: 11
Chapter 9. Namespace
Namespaces can be declared. The variables declared within a namespace can be used thanks to the :: operator
Example C09a.bas:
$CPP $NOMAIN #INCLUDE <iostream> NAMESPACE first RAW AS INT a RAW AS INT b END NAMESPACE NAMESPACE second RAW AS DOUBLE a RAW AS DOUBLE b END NAMESPACE FUNCTION MAIN() first::a = 2 first::b = 5 second::a = 6.453 second::b = 4.1e4 std::cout << first::a + second::a << std::endl std::cout << first::b + second::b << std::endl END FUNCTION
Result:
8.453 41005
Example C09b.bas: This example has a more BASIC-like feel to it
$CPP NAMESPACE first DIM ABC AS STRING ' ABC is a string END NAMESPACE NAMESPACE second DIM ABC AS DOUBLE ' ABC is a double precision number END NAMESPACE SUB MAIN first::ABC$ = "Here comes PI:" PRINT first::ABC$ ' $ sigil is required second::ABC = ATN(1) * 4 PRINT second::ABC# ' # sigil is required PAUSE END SUB
Chapter 10. Inline
If a function contains just simple lines of code, doesn't use for loops or the like, it can be declared inline. This means its code will be inserted everywhere the function is used. That's somewhat like a macro. The main advantage is the program will be faster. A small drawback is it will be bigger, because the full code of the function was inserted everywhere it is used.
Example C10.bas:
$CPP $NOMAIN #INCLUDE <iostream> inline FUNCTION hypothenuse (a AS DOUBLE, b AS DOUBLE) AS DOUBLE FUNCTION = SQRT(a * a + b * b) END FUNCTION FUNCTION MAIN () RAW AS DOUBLE k = 6, m = 9 ' Next two lines produce exactly the same result: std::cout << hypothenuse (k, m) << std::endl std::cout << SQRT(k * k + m * m) << std::endl END FUNCTION
Result:
10.8167 10.8167
Chapter 11. Exception
You know the classical control flow structures of C: FOR, IF, DO, WHILE ... C++ adds one more control structure named 'exception' consisting of members TRY, THROW, CATCH, and END TRY
Example C11.bas:
$CPP $NOMAIN #INCLUDE <iostream> FUNCTION MAIN () DIM AS INT a, b, c std::cout << "Type a number: " std::cin >> a std::cout << std::endl TRY IF a > 100 THEN THROW 100 IF a < 10 THEN THROW 10 c = a/3 THROW c CATCH (result AS INT) std::cout << "Result is: " << result << std::endl b = result + 1 END TRY std::cout << "b contains: " << b << std::endl std::cout << std::endl ' another example of EXCEPTION use: RAW zero [] = "zero" AS CHAR RAW even [] = "even" AS CHAR RAW notprime [] = "not prime" AS CHAR RAW prime [] = "prime" AS CHAR TRY IF a = 0 THEN THROW zero IF (a / 2) * 2 = a THEN THROW even XFOR INT i = 3 WHILE i <= SQRT((float)a) BY i++ std::cout << "Testing " << i << std::endl IF (a / i) * i = a THEN THROW notprime XNEXT THROW prime CATCH (conclusion AS CONST CHAR PTR) std::cout << "The number you typed is "<< conclusion << std::endl END TRY std::cout << std::endl END FUNCTION
Result:
Type a number: 5 Result is: 10 b contains: 11 The number you typed is prime
Chapter 12. Default Parameter Arguments
It is possible to define default parameters for functions.
Example C12.bas:
$CPP $NOMAIN #INCLUDE <iostream> FUNCTION test (a AS DOUBLE, b = 7 AS DOUBLE) AS DOUBLE FUNCTION = a - b END FUNCTION FUNCTION MAIN () std::cout << test (14, 5) << std::endl std::cout << test (14) << std::endl END FUNCTION
Result:
9 7
Chapter 13. Function Overload
One important advantage of C++ is the function overload. Several functions can be declared with the same name provided there is a difference in their parameter list. Different functions can have the same name provided something allows the compiler to distinguish between them: number of parameters, type of parameters...
Example C13.bas:
$CPP $NOMAIN #INCLUDE <iostream> FUNCTION test (a AS DOUBLE, b AS DOUBLE) AS DOUBLE FUNCTION = a + b END FUNCTION FUNCTION test (a AS INT, b AS INT) AS INT FUNCTION = a - b END FUNCTION FUNCTION MAIN () RAW AS DOUBLE m = 7, n = 4 RAW AS INT k = 5, p = 3 std::cout << test(m, n) << " , " << test(k, p) << std::endl END FUNCTION
Result:
11 , 2
Chapter 14. Operator Overload
Operator overloading can be used to redefine the basic symbolic operators for new kinds of parameters. The symbolic operators (+ - * / ...) can be defined for new data types.
Example C14.bas:
$CPP $NOMAIN #INCLUDE <iostream> TYPE bcx_vector DIM AS DOUBLE x DIM AS DOUBLE y END TYPE FUNCTION operator*(a AS DOUBLE, b AS bcx_vector) AS bcx_vector DIM AS bcx_vector r r.x = a * b.x r.y = a * b.y FUNCTION = r END FUNCTION FUNCTION MAIN () DIM AS bcx_vector k, m ' No need to type "struct bcx_vector" k.x = 2 ' To be able to write k.y = -1 ' k = bcx_vector (2, -1) m = 3.1415927 * k ' Magic! std::cout << "(" << m.x << ", " << m.y << ")" << std::endl END FUNCTION
Result:
(6.28319, -3.14159)
Chapter 15. Template function
Tired of defining the same function five times? One definition for *int* type parameters, one definition for *double* type parameters, one definition for *float* type parameters... Didn't you forget one type? What if a new data type is used? No problem: the C++ compiler can automatically generate every version of the function that is necessary! Just tell it how the function looks like by declaring a *template* function
Example C15.bas:
$CPP $NOMAIN #INCLUDE <iostream> TEMPLATE <class ttype> FUNCTION minimum (a AS ttype, b AS ttype) AS ttype RAW AS ttype r r = a IF b < a THEN r = b FUNCTION = r END FUNCTION END TEMPLATE FUNCTION MAIN () RAW AS INT i1, i2, i3 i1 = 34 i2 = 6 i3 = minimum (i1, i2) std::cout << "Most little: " << i3 << std::endl RAW AS DOUBLE d1, d2, d3 d1 = 7.9 d2 = 32.1 d3 = minimum (d1, d2) std::cout << "Most little: " << d3 << std::endl std::cout << "Most little: " << minimum (d3, 3.5) << std::endl END FUNCTION
Result:
Most little: 6 Most little: 7.9 Most little: 3.5
Chapter 16. NEW and DELETE
The keywords NEW and DELETE can be used to allocate and deallocate memory. They are cleaner than the functions malloc and free from standard C.
Example C16.bas:
$CPP $NOMAIN #INCLUDE <iostream> FUNCTION MAIN () RAW AS DOUBLE PTR d ' d is a variable whose purpose ' is to contain the address of a ' zone where a double is located d = NEW DOUBLE ' new allocates a zone of memory ' large enough to contain a double ' and returns its address. ' That address is stored in d. *d = 45.3 ' The number 45.3 is stored ' inside the memory zone ' whose address is given by d. std::cout << "Type a number: " std::cin >> *d *d = *d + 5 std::cout << "Result: " << *d << std::endl DELETE d ' delete deallocates the ' zone of memory whose address ' is given by pointer d. ' Now we can no more use that zone. d = NEW DOUBLE[15] ' allocates a zone for an array ' of 15 doubles. Note each 15 ' double will be constructed. ' This is pointless here but it ' is vital when using a data type ' that needs its constructor be ' used for each instance. d[0] = 4456 d[1] = d[0] + 567 std::cout << "Content of d[1]: " << d[1] << std::endl DELETE [] d ' delete [] will deallocate the ' memory zone. Note each 15 ' double will be destructed. ' This is pointless here but it ' is vital when using a data type ' that needs its destructor be ' used for each instance (the ~ ' method). Using delete without ' the [] would deallocate the ' memory zone without destructing ' each of the 15 instances. That ' would cause memory leakage. RAW AS INT n = 30 d = NEW DOUBLE[n] ' new can be used to allocate an ' array of random size. XFOR INT i = 0 WHILE i < n BY i++ d[i] = i XNEXT DELETE [] d DIM AS CHAR PTR s s = NEW CHAR[100] s$ = "Hello!" std::cout << s << std::endl DELETE [] s END FUNCTION
Result:
Type a number: 6 Result: 11 Content of d[1]: 5023 Hello!
Chapter 17. METHODS
In standard C a struct contains only data. In C++ a struct definition can also include functions. Those functions are owned by the struct and are meant to operate on the data of the struct. Those functions are called METHODS. The example below defines the method surface() on the struct vector.
Example C17.bas:
$CPP $NOMAIN #INCLUDE <iostream> PPTYPE bcx_vector RAW AS DOUBLE x RAW AS DOUBLE y FUNCTION surface () AS DOUBLE RAW AS DOUBLE s s = x * y IF s < 0 THEN s = -s FUNCTION = s END FUNCTION END PPTYPE FUNCTION MAIN () RAW AS bcx_vector a a.x = 3 a.y = 4 std::cout << "The surface of a: " << a.surface() << std::endl END FUNCTION
Result:
The surface of a: 12
Chapter 18. CONSTRUCTOR and DESTRUCTOR
Very special and essential methods are the CONSTRUCTOR and DESTRUCTOR. They are automatically called whenever an instance of a CLASS is created or destroyed (variable declaration, end of program, *new*, *delete*...).
The CONSTRUCTOR will initialize the variables of the instance, do some calculations, allocate some memory for the instance, output some text... whatever is needed.
Here is an example of a class definition with two overloaded constructors
Example C18.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y CONSTRUCTOR bcx_vector () ' same name as class x = 0 y = 0 END CONSTRUCTOR CONSTRUCTOR bcx_vector (a AS DOUBLE, b AS DOUBLE) x = a y = b END CONSTRUCTOR END CLASS FUNCTION MAIN () RAW AS bcx_vector k ' bcx_vector () is called std::cout << "bcx_vector k: " << k.x << ", " << k.y << std::endl << std::endl RAW AS bcx_vector m (45, 2) ' bcx_vector (double, double) is called std::cout << "bcx_vector m: " << m.x << ", " << m.y << std::endl << std::endl k = bcx_vector (23, 2) ' bcx_vector created, copied to k, then erased std::cout << "bcx_vector k: " << k.x << ", " << k.y << std::endl << std::endl END FUNCTION
Result:
vector k: 0, 0 vector m: 45, 2 vector k: 23, 2
Chapter 19. Complex classes
If you cast an object like a vector, everything will happen correctly. For example, if vector *k* contains *(4, 7)*, after the cast *m = k* the vector *m* will contain *(4, 7)* too. The values of k.x and k.y have simply been copied to m.x and m.y.
Now suppose you're playing with objects like the person class above. Those objects contain a pointer to a character string. If you cast the person object by writing *p = r* it is necesary that some function does the work to make *p* be a correct copy of *r*. Otherwise, p.name will point to the same physical character string as r.name. What's more, the former character string pointed to by p.name is lost and becomes a memory zombie. The result will be catastrophic: a mess of pointers and lost data. The methods that will do the job are the COPY CONSTRUCTOR and an overload of the = operator
Example C19.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS person PUBLIC: RAW AS CHAR PTR name RAW AS INT age CONSTRUCTOR person (n = "no name" AS CONST CHAR PTR, a = 0 AS INT) name = NEW CHAR[100] name$ = n$ age = a END CONSTRUCTOR CONSTRUCTOR person (s AS CONST person &) ' The COPY CONSTRUCTOR name = NEW CHAR[100] name$ = s.name$ age = s.age END CONSTRUCTOR FUNCTION operator= (s AS CONST person &) AS person& ' overload of = name$ = s.name$ age = s.age FUNCTION = *this END FUNCTION DESTRUCTOR ~person () DELETE [] name END DESTRUCTOR END CLASS SUB modify_person (h AS person&) h.age += 7 END SUB FUNCTION compute_person (h AS person) AS person h.age += 7 FUNCTION = h END FUNCTION FUNCTION MAIN () RAW AS person p std::cout << p.name << ", age " << p.age << std::endl << std::endl ' output: no name, age 0 RAW AS person k ("John", 56) std::cout << k.name << ", age " << k.age << std::endl << std::endl ' output: John, age 56 p = k std::cout << p.name << ", age " << p.age << std::endl << std::endl ' output: John, age 56 p = person ("Bob", 10) std::cout << p.name << ", age " << p.age << std::endl << std::endl ' output: Bob, age 10 ' Neither the copy constructor nor the overload ' of = are needed for this operation that modifies ' p since just the reference towards p is passed to ' the function modify_person: modify_person (p) std::cout << p.name << ", age " << p.age << std::endl << std::endl ' output: Bob, age 17 ' The copy constructor is called to pass a complete ' copy of p to the function compute_person. The ' function uses that copy to make its computations ' then a copy of that modified copy is made to ' return the result. Finally, the overload of = is ' called to paste that second copy inside k: k = compute_person (p) std::cout << p.name << ", age " << p.age << std::endl << std::endl ' output: Bob, age 17 std::cout << k.name << ", age " << k.age << std::endl << std::endl ' output: Bob, age 24 END FUNCTION
Result:
no name, age 0 John, age 56 John, age 56 Bob, age 10 Bob, age 17 Bob, age 17 Bob, age 24
The copy constructor allows your program to make copies of instances when doing calculations. It is a key method. During calculations, instances are created to hold intermediate results. They are modified, cast and destroyed without you being aware. This is why those methods can be useful even for simple objects (see Chapter 14.).
In all the examples above, the methods are defined inside the class definition. That automatically makes them inline methods.
Chapter 20. Method prototype
If a method cannot be inline, or you do not want it to be inline, or if you want the class definition to contain the minimum amount of information (or you simply want the usual separate .h header file and .cpp source code file), then you need only put the prototype of the method inside the class and define the method below the class (or in a separate .cpp source file).
Example C20.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y DIM FUNCTION surface() AS DOUBLE END CLASS test1,test2 FUNCTION bcx_vector::surface() AS DOUBLE RAW AS DOUBLE s = 0 XFOR DOUBLE i = 0 WHILE i < x BY i++ s = s + y XNEXT FUNCTION = s END FUNCTION FUNCTION MAIN () RAW AS bcx_vector k k.x = 4 k.y = 5 std::cout << "Surface: " << k.surface() << std::endl END FUNCTION
Result:
Surface: 20
Chapter 21. this
When a method is applied to an instance, that method may use the instance's variables, modify them... But sometimes it is necessary to know the address of the instance. No problem, the keyword *this* is intended for that purpose.
Example C21.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE) x = a y = b END CONSTRUCTOR FUNCTION module() AS DOUBLE FUNCTION = SQRT(x * x + y * y) END FUNCTION SUB set_length (a = 1 AS DOUBLE) RAW AS DOUBLE length length = this->module() x = x / length * a y = y / length * a END SUB END CLASS FUNCTION MAIN () RAW AS bcx_vector c (3, 5) std::cout << "The module of bcx_vector c: " << c.module() << std::endl c.set_length(2) ' Transforms c in a bcx_vector of size 2 std::cout << "The module of bcx_vector c: " << c.module() << std::endl c.set_length() ' Transforms b in an unitary bcx_vector. std::cout << "The module of bcx_vector c: " << c.module() << std::endl END FUNCTION
Result:
The module of vector c: 5.83095 The module of vector c: 2 The module of vector c: 1
Chapter 22. Arrays
Of course, it is possible to declare arrays of objects.
Example C22.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE) x = a y = b END CONSTRUCTOR FUNCTION module () AS DOUBLE FUNCTION = SQRT(x * x + y * y) END FUNCTION END CLASS FUNCTION MAIN () RAW AS bcx_vector s[1000] RAW AS bcx_vector t[3] = {bcx_vector(4, 5), bcx_vector(5, 5), bcx_vector(2, 4)} s[23] = t[2] std::cout << t[0].module() << std::endl END FUNCTION
Result:
6.40312
Chapter 23. Class declaration
Here is an example of a full class declaration.
Example C23.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y DIM CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE) DIM CONSTRUCTOR bcx_vector () DIM FUNCTION operator + (a AS bcx_vector) AS bcx_vector DIM FUNCTION operator - (a AS bcx_vector) AS bcx_vector DIM FUNCTION operator - () AS bcx_vector DIM FUNCTION operator * (a AS DOUBLE) AS bcx_vector DIM FUNCTION module() AS DOUBLE DIM SUB set_length (A AS DOUBLE = 1) END CLASS CONSTRUCTOR bcx_vector::bcx_vector (a AS DOUBLE, b AS DOUBLE) x = a y = b END CONSTRUCTOR CONSTRUCTOR bcx_vector::bcx_vector () x = 0 y = 0 END CONSTRUCTOR FUNCTION bcx_vector::operator + (a AS bcx_vector) AS bcx_vector FUNCTION = bcx_vector (x + a.x, y + a.y) END FUNCTION FUNCTION bcx_vector::operator - (a AS bcx_vector) AS bcx_vector FUNCTION = bcx_vector (x - a.x, y - a.y) END FUNCTION FUNCTION bcx_vector::operator - () AS bcx_vector FUNCTION = bcx_vector (-x, -y) END FUNCTION FUNCTION bcx_vector::operator * (a AS DOUBLE) AS bcx_vector FUNCTION = bcx_vector (x * a, y * a) END FUNCTION FUNCTION bcx_vector::module() AS DOUBLE FUNCTION = SQRT(x * x + y * y) END FUNCTION SUB bcx_vector::set_length (a AS DOUBLE) RAW AS DOUBLE length = this->module() x = x / length * a y = y / length * a END SUB FUNCTION operator << (o AS std::ostream&, a AS bcx_vector) AS std::ostream& o << "(" << a.x << ", " << a.y << ")"; FUNCTION = o END FUNCTION FUNCTION MAIN () RAW AS bcx_vector a RAW AS bcx_vector b RAW AS bcx_vector c (3, 5) a = c * 3 a = b + c c = b - c + a + (b - a) * 7 c = -c std::cout << "The module of bcx_vector c: " << c.module() << std::endl std::cout << "The content of bcx_vector a: " << a << std::endl std::cout << "The opposite of bcx_vector a: " << -a << std::endl c.set_length(2) ' Transforms c in a bcx_vector of size 2. a = bcx_vector (56, -3) b = bcx_vector (7, c.y) b.set_length() ' Transforms b in an unitary bcx_vector. std::cout << "The content of bcx_vector b: " << b << std::endl DIM AS DOUBLE k k = bcx_vector(1, 1).module() ' k will contain 1.4142. std::cout << "k contains: " << k << std::endl END FUNCTION
Result:
The module of bcx_vector c: 40.8167 The content of bcx_vector a: (3, 5) The opposite of bcx_vector a: (-3, -5) The content of bcx_vector b: (0.971275, 0.23796) k contains: 1.41421
Chapter 23a. Class declaration with destructor.
A destructor has been added to the Chapter 23 example to show the use of the tilde "~" with destructors.
Example C23a.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y DIM CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE) DIM CONSTRUCTOR bcx_vector () 'need ~ below DIM DESTRUCTOR ~bcx_vector() DIM FUNCTION operator + (a AS bcx_vector) AS bcx_vector DIM FUNCTION operator - (a AS bcx_vector) AS bcx_vector DIM FUNCTION operator - () AS bcx_vector DIM FUNCTION operator * (a AS DOUBLE) AS bcx_vector DIM FUNCTION module() AS DOUBLE DIM SUB set_length (A AS DOUBLE = 1) END CLASS CONSTRUCTOR bcx_vector::bcx_vector (a AS DOUBLE, b AS DOUBLE) x = a y = b END CONSTRUCTOR CONSTRUCTOR bcx_vector::bcx_vector () x = 0 y = 0 END CONSTRUCTOR 'need ~ below DESTRUCTOR bcx_vector::~bcx_vector() END DESTRUCTOR FUNCTION bcx_vector::operator + (a AS bcx_vector) AS bcx_vector FUNCTION = bcx_vector (x + a.x, y + a.y) END FUNCTION FUNCTION bcx_vector::operator - (a AS bcx_vector) AS bcx_vector FUNCTION = bcx_vector (x - a.x, y - a.y) END FUNCTION FUNCTION bcx_vector::operator - () AS bcx_vector FUNCTION = bcx_vector (-x, -y) END FUNCTION FUNCTION bcx_vector::operator * (a AS DOUBLE) AS bcx_vector FUNCTION = bcx_vector (x * a, y * a) END FUNCTION FUNCTION bcx_vector::module() AS DOUBLE FUNCTION = SQRT(x * x + y * y) END FUNCTION SUB bcx_vector::set_length (a AS DOUBLE) RAW AS DOUBLE length = this->module() x = x / length * a y = y / length * a END SUB FUNCTION operator << (o AS std::ostream&, a AS bcx_vector) AS std::ostream& o << "(" << a.x << ", " << a.y << ")"; FUNCTION = o END FUNCTION FUNCTION MAIN () RAW AS bcx_vector a RAW AS bcx_vector b RAW AS bcx_vector c (3, 5) a = c * 3 a = b + c c = b - c + a + (b - a) * 7 c = -c std::cout << "The module of bcx_vector c: " << c.module() << std::endl std::cout << "The content of bcx_vector a: " << a << std::endl std::cout << "The oposite of bcx_vector a: " << -a << std::endl c.set_length(2) ' Transforms c in a bcx_vector of size 2. a = bcx_vector (56, -3) b = bcx_vector (7, c.y) b.set_length() ' Transforms b in an unitary bcx_vector. std::cout << "The content of bcx_vector b: " << b << std::endl DIM AS DOUBLE k k = bcx_vector(1, 1).module() ' k will contain 1.4142. std::cout << "k contains: " << k << std::endl END FUNCTION
Result:
The module of bcx_vector c: 40.8167 The content of bcx_vector a: (3, 5) The opposite of bcx_vector a: (-3, -5) The content of bcx_vector b: (0.971275, 0.23796) k contains: 1.41421
Chapter 24. Static variables
One or more variables in a class can be declared *static*. In which case, only one instance of those variables exist, shared by all instances of the class. It must be initialised outside the class declaration.
Example C24.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y STATIC AS INT count CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE) x = a y = b count++ END CONSTRUCTOR DESTRUCTOR ~bcx_vector() count-- END DESTRUCTOR END CLASS RAW AS INT bcx_vector::count = 0 FUNCTION MAIN () std::cout << "Number of bcx_vectors:" << std::endl RAW AS bcx_vector a std::cout << bcx_vector::count << std::endl RAW AS bcx_vector b std::cout << bcx_vector::count << std::endl RAW AS bcx_vector PTR r, u r = NEW bcx_vector std::cout << bcx_vector::count << std::endl u = NEW bcx_vector std::cout << a.count << std::endl DELETE r std::cout << bcx_vector::count << std::endl DELETE u std::cout << b.count << std::endl END FUNCTION
Result:
Number of bcx_vectors: 1 2 3 4 3 2
Chapter 25. Const variables
A class variable can also be *const*ant. That's just like static, except it is given a value inside the class declaration and that value cannot be modified.
☞ A const within a CLASS must be a static const of integral or enumeration type initialized by a constant expression.
Some compilers, for example g++, have an extension that allows for const static float and doubles within a CLASS. Also, the C++0x standard has introduced a new type, constexpr, which allows in-CLASS float and doubles constants.
Example C25.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y CONST STATIC INT piint = 3 CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE) x = a y = b END CONSTRUCTOR FUNCTION cylinder_volume () AS DOUBLE FUNCTION = x * x / 4 * (piint + 0.14159) * y END FUNCTION END CLASS FUNCTION MAIN () std::cout << "The value of pi: " << bcx_vector::piint + 0.14159 << std::endl << std::endl bcx_vector k (3, 4) std::cout << "Result: " << k.cylinder_volume() << std::endl END FUNCTION
Result:
The value of pi: 3.14159 Result: 28.2743
Chapter 26. Derived Class.
A class can be derived from another class. The new class inherits the variables and methods of the base class. Additional variables and/or methods can be added.
Example C26.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE) x = a y = b END CONSTRUCTOR FUNCTION module() AS DOUBLE FUNCTION = SQRT(x*x + y*y) END FUNCTION FUNCTION surface() AS DOUBLE FUNCTION = x * y END FUNCTION END CLASS CLASS trivector USING PUBLIC bcx_vector ' trivector is derived from bcx_vector PUBLIC: RAW AS DOUBLE z ' added to x and y from bcx_vector CONSTRUCTOR trivector (m=0 AS DOUBLE, n=0 AS DOUBLE, p=0 AS DOUBLE) USING bcx_vector (m, n) z = p ' bcx_vector constructor will END CONSTRUCTOR ' be called before trivector ' constructor, with parameters ' m and n. CONSTRUCTOR trivector (a AS bcx_vector) ' What to do if a bcx_vector is cast to a trivector x = a.x y = a.y z = 0 END CONSTRUCTOR FUNCTION module () AS DOUBLE ' define module() for trivector FUNCTION = SQRT(x*x + y*y + z*z) END FUNCTION FUNCTION volume () AS DOUBLE FUNCTION = this->surface() * z ' or x * y * z END FUNCTION END CLASS FUNCTION MAIN () RAW AS bcx_vector a (4, 5) RAW AS trivector b (1, 2, 3) std::cout << "a (4, 5) b (1, 2, 3) *r = b" << std::endl << std::endl std::cout << "Surface of a: " << a.surface() << std::endl std::cout << "Volume of b: " << b.volume() << std::endl std::cout << "Surface of base of b: " << b.surface() << std::endl std::cout << "Module of a: " << a.module() << std::endl std::cout << "Module of b: " << b.module() << std::endl std::cout << "Module of base of b: " << b.bcx_vector::module() << std::endl RAW AS trivector k k = a ' thanks to trivector(bcx_vector) definition ' copy of x and y, k.z = 0 RAW AS bcx_vector j j = b ' copy of x and y. b.z left out RAW AS bcx_vector PTR r r = &b std::cout << "Surface of r: " << r->surface() << std::endl std::cout << "Module of r: " << r->module() << std::endl END FUNCTION
Result:
a (4, 5) b (1, 2, 3) *r = b Surface of a: 20 Volume of b: 6 Surface of base of b: 2 Module of a: 6.40312 Module of b: 3.74166 Module of base of b: 2.23607 Surface of r: 2 Module of r: 2.23607
Chapter 27. Virtual method
In the Chapter 26 example, *r->module()* calculates the vector module, using *x* and *y*, because *r* has been declared a vector pointer. The fact that *r* actually points to a trivector is not taken into account. If you want the program to check the type of the pointed object and choose the appropriate method, then you must declare that method as *virtual* inside the base class.
(If at least one of the methods of the base class is virtual then a "header" of 4 bytes is added to every instance of the classes. This allows the program to determine what a vector actually points to.) (4 bytes is probably implementation specific. On a 64 bit machine maybe it is 8 bytes...)
Example C27.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE) x = a y = b END CONSTRUCTOR FUNCTION module() AS virtual DOUBLE FUNCTION = SQRT(x*x + y*y) END FUNCTION END CLASS CLASS trivector USING PUBLIC bcx_vector PUBLIC: RAW AS DOUBLE z CONSTRUCTOR trivector (m = 0 AS DOUBLE, n = 0 AS DOUBLE, p = 0 AS DOUBLE) x = m ' Just for the game, y = n ' here I do not call the bcx_vector z = p ' constructor and I make the END CONSTRUCTOR ' trivector constructor do the ' whole job. Same result. FUNCTION module () AS DOUBLE FUNCTION = SQRT(x*x + y*y + z*z) END FUNCTION END CLASS SUB test (k AS bcx_vector &) std::cout << "Test result: " << k.module() << std::endl END SUB FUNCTION MAIN () RAW AS bcx_vector a (4, 5) RAW AS trivector b (1, 2, 3) std::cout << "a (4, 5) b (1, 2, 3)" << std::endl << std::endl RAW AS bcx_vector PTR r r = &a std::cout << "module of bcx_vector a: " << r->module() << std::endl r = &b std::cout << "module of trivector b: " << r->module() << std::endl test (a) test (b) RAW AS bcx_vector &s = b std::cout << "module of trivector b: " << s.module() << std::endl END FUNCTION
Result:
a (4, 5) b (1, 2, 3) module of bcx_vector a: 6.40312 module of trivector b: 3.74166 Test result: 6.40312 Test result: 3.74166 module of trivector b: 3.74166
Chapter 28. Multi-class method
Maybe you wonder if a class can be derived from more than one base class. The answer is yes.
Example C28.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE) x = a y = b END CONSTRUCTOR FUNCTION surface() AS DOUBLE FUNCTION = fabs (x * y) END FUNCTION END CLASS CLASS number PUBLIC: RAW AS DOUBLE z CONSTRUCTOR number (a AS DOUBLE) z = a END CONSTRUCTOR FUNCTION is_negative () AS INT IF z < 0 THEN FUNCTION = 1 ELSE FUNCTION = 0 END IF END FUNCTION END CLASS CLASS trivector USING PUBLIC bcx_vector, PUBLIC number PUBLIC: CONSTRUCTOR trivector(a=0 AS DOUBLE, b=0 AS DOUBLE, c=0 AS DOUBLE) USING bcx_vector(a,b), number(c) END CONSTRUCTOR ' The trivector constructor calls the bcx_vector ' constructor, then the number constructor, ' and in this example does nothing more. FUNCTION volume() AS DOUBLE FUNCTION = fabs (x * y * z) END FUNCTION END CLASS FUNCTION MAIN () RAW AS trivector a(2, 3, -4) std::cout << a.volume() << std::endl std::cout << a.surface() << std::endl std::cout << a.is_negative() << std::endl END FUNCTION
Result:
24 6 1
Chapter 29. Derived Class
Class derivation allows you to construct more complex classes built from base classes. There is another application of class derivation: allowing the programmer to write generic functions.
Suppose you define a base class with no variables. It makes no sense to use instances of that class inside your program. But then you write a function whose purpose it is to sort instances of that class. That function will be able to sort any type of object provided it belongs to a class derived from that base class! The only condition is that inside of each derived class definition, all methods that the sort function needs are correctly defined.
Example C29.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS octopus PUBLIC: IMPFUNCTION module() = 0 AS virtual DOUBLE ' = 0 implies function is not ' defined. This makes instances ' of this CLASS cannot be declared. END CLASS FUNCTION biggest_module (a AS octopus &, b AS octopus &, c AS octopus &) AS DOUBLE RAW r = a.module() AS DOUBLE IF b.module() > r THEN r = b.module() IF c.module() > r THEN r = c.module() FUNCTION = r END FUNCTION CLASS bcx_vector USING PUBLIC octopus PUBLIC: RAW AS DOUBLE x RAW AS DOUBLE y CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE) x = a y = b END CONSTRUCTOR FUNCTION module() AS DOUBLE FUNCTION = SQRT(x * x + y * y) END FUNCTION END CLASS CLASS number USING PUBLIC octopus PUBLIC: RAW AS DOUBLE n CONSTRUCTOR number (a = 0 AS DOUBLE) n = a END CONSTRUCTOR FUNCTION module() AS DOUBLE IF n >= 0 THEN FUNCTION = n FUNCTION = -n END FUNCTION END CLASS FUNCTION MAIN () RAW AS bcx_vector k (1,2), m (6,7), n (100, 0) RAW AS number p (5), q (-3), r (-150) std::cout << biggest_module (k, m, n) << std::endl std::cout << biggest_module (p, q, r) << std::endl std::cout << biggest_module (p, q, n) << std::endl END FUNCTION
Result:
100 150 100
Chapter 30. Encapsulation: public, protected and private
The *PUBLIC:* directive means the variables or the methods below can be accessed and used everywhere in the program.
If you want the variables and methods to be accessible only to methods of the class AND to methods of derived classes, then you must put the keyword *protected:* before them.
If you want variables or methods to be accessible ONLY to methods of the class, then you must put the keyword *private:* before them.
The fact that variables or methods are declared private or protected means that nothing external to the class can access or use them. That's ENCAPSULATION. (If you want to give a specific function the right to access those variables and methods, then you must include that function's prototype inside the class definition, preceded by the keyword *friend*.)
Good practice is to encapsulate all the variables of a class. This can sound strange if you're used to structs in C. Indeed a struct only makes sense if you can access its data... In C++ you have to create methods to access the data inside a class. The example below uses the basic example of chapter 17, yet declares the class data to be protected.
Example C30_01.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PROTECTED: RAW AS DOUBLE x RAW AS DOUBLE y PUBLIC: SUB set_x (n AS INT) x = n END SUB SUB set_y (n AS INT) y = n END SUB FUNCTION surface () AS DOUBLE RAW AS DOUBLE s s = x * y IF s < 0 THEN s = -s FUNCTION = s END FUNCTION END CLASS FUNCTION MAIN () RAW AS bcx_vector a a.set_x (3) a.set_y (4) std::cout << "The surface of a: " << a.surface() << std::endl END FUNCTION
Result:
The surface of a: 12
The example above is a bit odd since the class data x and y can be set but they cannot be read back. Any attempt in function main () to read a.x or a.y will result in a compilation error. In the next example, x and y can be read back.
Example C30_02.bas:
$CPP $NOMAIN #INCLUDE <iostream> CLASS bcx_vector PROTECTED: RAW AS DOUBLE x RAW AS DOUBLE y PUBLIC: SUB set_x (n AS INT) x = n END SUB SUB set_y (n AS INT) y = n END SUB FUNCTION get_x () AS DOUBLE FUNCTION = x END FUNCTION FUNCTION get_y () AS DOUBLE FUNCTION = y END FUNCTION FUNCTION surface () AS DOUBLE RAW AS DOUBLE s s = x * y IF s < 0 THEN s = -s FUNCTION = s END FUNCTION END CLASS FUNCTION MAIN () RAW AS bcx_vector a a.set_x (3) a.set_y (4) std::cout << "The surface of a: " << a.surface() << std::endl std::cout << "The width of a: " << a.get_x() << std::endl std::cout << "The height of a: " << a.get_y() << std::endl END FUNCTION
Result:
The surface of a: 12 The width of a: 3 The height of a: 4
Chapter 31. Brief examples of file I/O
Let's talk about input/output. In C++ that's a very broad subject. Here is a program that writes to a file
Example C31_01.bas:
$CPP $NOMAIN #INCLUDE <iostream> #INCLUDE <fstream> FUNCTION MAIN () RAW AS std::fstream f f.open("test.txt", std::ios::out) f << "This is a text output to a file." << std::endl RAW AS DOUBLE a = 345 f << "A number: " << a << std::endl f.close() std::cout << "test.txt created" << std::endl END FUNCTION
Result:
test.txt created
The content of file test.txt should be
This is a text output to a file. A number: 345
Before you use Example C31_02 be sure to create the test.txt file with Example C31_01.
Example C31_02.bas:
$CPP $NOMAIN #INCLUDE <iostream> #INCLUDE <fstream> FUNCTION MAIN () RAW AS std::fstream f RAW AS CHAR c std::cout << "What's inside the test.txt file" << std::endl std::cout << std::endl f.open("test.txt", std::ios::in) WHILE NOT f.eof() f.get(c) 'Or c = f.get() std::cout << c WEND f.close() END FUNCTION
Result:
What's inside the test.txt file This is a text output to a file. A number: 345
Chapter 32. Character arrays
Generally speaking, it is possible to do on character arrays the same operations as on files. This is very useful to convert data or manage memory arrays.
Here is a program that writes inside a character array.
Example C32_01.bas:
$CPP $NOMAIN #INCLUDE <iostream> #INCLUDE <strstream> FUNCTION MAIN () RAW AS CHAR a[1024] RAW AS std::ostrstream b(a, 1024) b.seekp(0) ' Start from first char. b << "2 + 2 = " << 2 + 2 << std::ends ' ( ends, not std::endl ) ' ends is simply the ' null character '\0' std::cout << a << std::endl RAW AS DOUBLE v = 2 a$ = "A sinus: " b.seekp(LEN(a)) b << "sin (" << v << ") = " << SIN(v) << std::ends std::cout << a << std::endl END FUNCTION
Result:
2 + 2 = 4 A sinus: sin (2) = 0.909297
A program that reads from a character string
Example C32_02.bas:
$CPP $NOMAIN #INCLUDE <iostream> #INCLUDE <strstream> FUNCTION MAIN () RAW AS CHAR a[1024] RAW AS std::istrstream b(a, 1024) a$ = "45.656" RAW AS DOUBLE k, p b.seekg(0) ' Start from first character. b >> k k = k + 1 std::cout << k << std::endl a$ = "444.23 56.89" b.seekg(0) b >> k >> p std::cout << k << ", " << p + 1 << std::endl END FUNCTION
Result:
46.656 444.23, 57.89
Chapter 33. Formatted output
This program performs formatted output two different ways. Please note the *width()* and *setw()* MODIFIERS are only effective on the next item output to the stream. Subsequent items will not be influenced.
Example C33.bas:
$CPP $NOMAIN #INCLUDE <iostream> #INCLUDE <iomanip> FUNCTION MAIN () RAW AS INT i std::cout << "A list of numbers:" << std::endl XFOR i = 1 WHILE i <= 1024 BY i *= 2 std::cout.width (7) std::cout << i << std::endl XNEXT std::cout << "A table of numbers:" << std::endl XFOR i = 0 WHILE i <= 4 BY i++ std::cout << std::setw(3) << i << std::setw(5) << i * i * i << std::endl XNEXT END FUNCTION
Result:
A list of numbers: 1 2 4 8 16 32 64 128 256 512 1024 A table of numbers: 0 0 1 1 2 8 3 27 4 64
METHOD and PROPERTY keywords
METHOD is transformed to FUNCTION and PROPERTY is transformed to SUB prior to main BCX translation. METHOD and PROPERTY can only be used in a CLASS which can only be compiled with a C++ compiler in C++ mode.
Example:
$CPP SUB MAIN DIM RAW AS bcx_vector a a.set_x (3) a.set_y (4) PRINT "The surface of a: ", a.surface#() END SUB CLASS bcx_vector PROTECTED: DIM RAW AS DOUBLE x DIM RAW AS DOUBLE y PUBLIC: PROPERTY set_x (n AS DOUBLE) x = n END PROPERTY PROPERTY set_y (n AS DOUBLE) y = n END PROPERTY METHOD surface () AS DOUBLE DIM RAW AS DOUBLE s s = x * y IF s < 0 THEN s = -s METHOD = s END METHOD END CLASS
Result:
The surface of a: 12
PROPGET and PROPSET keywords
PROPGET is transformed to FUNCTION and PROPSET is transformed to SUB prior to main BCX translation. PROPGET and PROPSET can only be used in a CLASS which can only be compiled with a C++ compiler in C++ mode.
Example:
$CPP OPTION BASE 1 DIM Vehicle [3] AS CAR FOR INTEGER i = 1 TO 3 '******************************************************************** ' Every car starts out as a Black Volkswagon with 2 gallons of fuel '******************************************************************** PRINT "Vehicle:", i, " is a ", _ Vehicle[i].Get_Paint$(), " ", _ Vehicle[i].Get_Model$(), " with", _ Vehicle[i].Get_Fuel () , " gallons of fuel." NEXT PRINT '*********************************************************************** ' Now let's trade our Volkswagons in on some muscle cars! '*********************************************************************** Vehicle[1].Set_Model ("Chevrolet Corvette") Vehicle[1].Set_Paint ("White") Vehicle[1].Set_Fuel (10) Vehicle[2].Set_Model ("Ford Mustang") Vehicle[2].Set_Paint ("Blue") Vehicle[2].Set_Fuel (5) Vehicle[3].Set_Model ("Dodge Charger") Vehicle[3].Set_Paint ("Green") Vehicle[3].Set_Fuel (13) FOR INTEGER i = 1 TO 3 PRINT "Vehicle:", i, " is a ", _ Vehicle[i].Get_Paint$(), " ", _ Vehicle[i].Get_Model$(), " with", _ Vehicle[i].Get_Fuel(), " gallons of fuel." NEXT PAUSE '******************************************************************** ' Here is our CLASS named "CAR". Each instance of "CAR" contains a ' CONSTRUCTOR, 3 variables, 3 "Setters", 3 "Getters" and a function '******************************************************************** CLASS CAR PROTECTED: DIM Model$, Paint$, Fuel ' << These are our car PROPERTIES '***************************************************************** ' A CONSTRUCTOR is like a SUB that is called automatically when ' a new instance of CAR is created. CONSTRUCTOR names must use ' the same name as the CLASS that it is stored within. That is ' why our CLASS and CONSTRUCTOR are both named "CAR". That is ' a C++ rule and therefore also a BCX rule. '***************************************************************** PUBLIC: CONSTRUCTOR CAR (M$ = "Volkswagon", P$ = "BLACK", F = 2 ) Model$ = M$ Paint$ = P$ Fuel = F END CONSTRUCTOR '***************************************************************** ' Here are our property "SETTERS" '***************************************************************** PROPSET Set_Model (M$) Model$ = M$ END PROPSET PROPSET Set_Paint (c$) Paint$ = c$ END PROPSET PROPSET Set_Fuel (x AS INTEGER) Fuel = x END PROPSET '***************************************************************** ' Here are our property "GETTERS" '***************************************************************** PROPGET Get_Model() AS STRING PROPGET = MixCase$ (Model$) ' Uses our helper function (below) END PROPGET PROPGET Get_Fuel() AS INTEGER PROPGET = Fuel END PROPGET PROPGET Get_Paint() AS STRING PROPGET = MixCase$ (Paint$) ' Uses our helper function (below) END PROPGET '***************************************************************** ' Here is a user-defined helper FUNCTION '***************************************************************** FUNCTION MixCase$(A$) ' Here is a local User-Defined Function FUNCTION = MCASE$(A$) ' calling a built-in BCX string function END FUNCTION END CLASS
Result:
Vehicle: 1 is a Black Volkswagon with 2 gallons of fuel. Vehicle: 2 is a Black Volkswagon with 2 gallons of fuel. Vehicle: 3 is a Black Volkswagon with 2 gallons of fuel. Vehicle: 1 is a White Chevy Corvette with 10 gallons of fuel. Vehicle: 2 is a Blue Ford Mustang with 5 gallons of fuel. Vehicle: 3 is a Green Dodge Charger with 13 gallons of fuel.
RBFOR, RBEXIT, and RBNEXT keywords
Purpose: RBFOR, RBEXIT, and RBNEXT support C++range-based FOR ... NEXT loops. These require a C++11 or newer compiler.
Syntax: RBFOR(DataType iteranger : iteratee) Statements [ RBEXIT RBFOR ] RBNEXT Parameters:
|
Remarks:
RBEXIT RBFOR can be used to exit the loop. Functionality is identical to EXIT FOR.Example
The following example iterates through the named directory, in this code the D:/t directory, and prints any entries that have a .exe, .c, or .cpp extension.
☞ This example requires a compiler conforming, at minimum, to the C++17 standard.
$CPP $CPPHDR #INCLUDE <filesystem> FUNCTION MAIN() RAW AS std::filesystem::path p = "C:\temp" ' Modify to suit your needs DIM S1$ IF std::filesystem::exists(p) THEN IF std::filesystem::is_directory(p) THEN RBFOR(AUTO& e : std::filesystem::recursive_directory_iterator(p)) S1$ = e.path().string().c_str() ' Be careful not to accidentally change case IF (UCASE$(BCXSPLITPATH$(S1$, FEXT)) = ".EXE") OR _ (UCASE$(BCXSPLITPATH$(S1$, FEXT)) = ".C") OR _ (UCASE$(BCXSPLITPATH$(S1$, FEXT)) = ".CPP") THEN PRINT S1$ END IF RBNEXT ENDIF ELSE PRINT "Specified drive, path, and/or file extensions not found." END IF PRINT "ALL Done" PAUSE END FUNCTION