Rapid-Q Documentation by William Yu (c)1999-2000 | Chapter 3

# 3. Rapid-Q Language Guide

  In this chapter, I'll go through the language of BASIC, specifically Rapid-Q. Since Rapid-Q is derived from the BASIC language, most experienced BASIC programmers can skim this section if you so choose. There's a few new concepts that is not part of the BASIC language like infinite parameter passing and using the '-' operator on strings.
  3.1 Rapid-Q Directives
  Directives are used in Rapid-Q to tell the compiler how, and what kind of code is to be generated. Rapid-Q supports the following directives, which are usually included at the beginning of your programs.

  | $APPTYPE |  | [ CGI | CONSOLE | GUI ] Default is GUI $APPTYPE is used to tell the compiler what kind of application you want generated. Although the default is GUI, if no $APPTYPE directive is used, Rapid-Q will detect what kind of application your program is just by looking at the source code. To override this feature, include the $APPTYPE directive at the beginning of your source code.
  Usage: $APPTYPE CONSOLE
  | $TYPECHECK |  | [ OFF | ON ] Default is OFF $TYPECHECK is used to tell the compiler whether you want the source code parsed using strict type checking ON (all variables must be declared), or relaxed type checking OFF like traditional BASIC where you don't need to declare your variables. Note, you can turn ON or OFF type checking at anytime, so you can type check a portion of your code and turn it OFF afterwards.
  Usage: $TYPECHECK ON
  | $INCLUDE |  | [ FileName ] Using $INCLUDE has the same effect as importing your file directly into your program at the point of call. You can use $INCLUDE anywhere in your program, except in a SUB or FUNCTION, but is most often included at the beginning of your source code. Enclosing the filename between quotes will search for that file in the current directory, and specified include paths. Enclosing the filename between < and > will search for that file in the current directory, specified include paths and the environment search paths.
  Usage:
  $INCLUDE "RAPIDQ.INC"
  $INCLUDE <RAPIDQ.INC>
  | $RESOURCE |  | Handle AS FileName Most Windows programming languages include support for Resource files. In Rapid-Q, this is somewhat different. In Rapid-Q, Resource files are just a collection of graphics files. There is no such thing as resource strings in Rapid-Q. Anyway, what's great about Resource files is that they are embedded into your applications. So if you're using 10 different bitmaps, you don't need to include them in your .ZIP distribution because it's already embedded into the .EXE. Enclosing the filename between quotes will search for that file in the current directory, and specified include paths. Enclosing the filename between < and > will search for that file in the current directory, specified include paths and the environment search paths.
  Usage:
  $RESOURCE RES_BMP1 AS "CLOUDS.BMP"
  $RESOURCE RES_BMP1 AS <CLOUDS.BMP>
  | $DEFINE |  | NewDefinition [OldDefinition] When you feel like redefining or creating new keywords/tokens, use this directive. You cannot construct a series of tokens to be redefined. You cannot redefine operators or punctuations. $DEFINE cannot be used to define a function (like in C). The OldDefinition parameter is optional, so you can do this just fine: $DEFINE NEWDEF
  Usage: $DEFINE INT16 SHORT
  | $UNDEF |  | DefName [, DefName] To undefine a previous call of define, use $UNDEF. You can specify multiple instances on the same line, separated with commas. Usage: $UNDEF INT16, INT32
  | $IFDEF |  | Definition This directive is used to specify whether a piece of code should or should not be compiled. It is used in conjunction with $DEFINE. If the Definition has been defined, the code within the $IFDEF..$ENDIF statement will be compiled, otherwise it is skipped entirely.
  Usage:
  $IFDEF INT16
  ' if INT16 has been defined
  ' compile this portion
  $ELSE
  ' if INT16 has not been defined
  ' compile this portion
  $ENDIF
  | $IFNDEF |  | Definition $IFNDEF has the opposite effect as $IFDEF. Usage: $IFNDEF INT16 ' if INT16 has not been defined
  ' compile this portion
  $ELSE
  ' if INT16 has been defined
  ' compile this portion
  $ENDIF
  | $OPTION |  | OptionName [Parameters] BYREF, BYTECODE, DECIMAL, DIM, EXPLICIT, GTK, ICON, INKEY$, and WEAKTYPE are valid OptionNames. Usage: $OPTION BYREF This changes the way variables are
  passed. By default, Rapid-Q passes variables
  by value. This option reverses that.
  Use with caution.
  $OPTION BYTECODE
  Compile as byte code only.
  $OPTION DECIMAL ","
  $OPTION DECIMAL 64
  This changes the default decimal
  character for use in VAL.
  The default decimal character is the period.
  $OPTION DIM BYTE
  $OPTION DIM WORD
  $OPTION DIM DWORD
  $OPTION DIM SHORT
  $OPTION DIM INTEGER
  $OPTION DIM LONG
  $OPTION DIM SINGLE
  $OPTION DIM DOUBLE
  $OPTION DIM STRING
  $OPTION DIM VARIANT
  This changes the default type
  for an undeclared variable.
  By default, all undeclared variables are
  assumed to be of type DOUBLE
  if no suffix is provided.
  $OPTION EXPLICIT
  Same as using TYPECHECK ON
  Maintained for compatibility with VB
  $OPTION GTK
  Uses GTK instead of XFORMS
  Make sure you have the proper files
  $OPTION ICON "path\file.ico"
  This changes the default icon
  of your executable file.
  $OPTION INKEY$ DEFAULT
  $OPTION INKEY$ TRAPALL
  This allows INKEY$ to accept/reject
  certain extended characters.
  TRAPALL will trap Shift/Ctrl/Alt/Menu
  as well as Caps/Num/Scroll lock.
  $OPTION VBDLL ON
  $OPTION VBDLL OFF
  This determines how DLLs are handled.
  If VBDLL is enabled (ON), your DLL
  declarations in Rapid-Q will mimic VB's
  such that your code can be used the
  same way in both languages.
  This option is OFF by default.
  $OPTION WEAKTYPE ON
  $OPTION WEAKTYPE OFF
  WeakType is disabled (OFF) by default
  WeakType allows for faster parsing
  and may help in porting some VB code.
  It should not generally be used,
  unless you know the code is okay.
  | $OPTIMIZE |  | [ OFF | ON ] Default is OFF $OPTIMIZE can be used to reduce the byte code size by eliminating unnecessary instructions. If you use this option, make sure it's one of the first things you call. Usage: $OPTIMIZE ON
  | $ESCAPECHARS |  | [ OFF | ON ] Default is OFF If $ESCAPECHARS is turned ON, you can use escape sequences in your strings. Escape sequences can either be character or numeric escapes. Note that case is sensitive. Usage: $ESCAPECHARS ON

  Escape sequence | Details
  \a \b \f \n \r
  \t
  \v
  \\
  \"
  \###
  \xHH
  Alarm bell
  Backspace
  Form feed
  New line
  Carriage return
  Horizontal Tab
  Vertical Tab
  Backslash
  Double quote
  ### is any number 0..255
  HH is a hexidecimal value 00..FF

  Examples:
  PRINT "\""
  Output is "
  PRINT "\x41"
  Output is A
  PRINT "\t\65\66\67\t\68\69\70
  Output is ABC DEF
  PRINT "Hey\r\n";
  Output is Hey with newline
  | $MACRO |  | MacroName[(Parameters, ...)] MacroDefinition A Macro simply replaces a definition with another. It can be treated like a function if you supply parameters. Rapid-Q allows Macros to be embedded within another Macro (foward only to avoid recursion), token pasting using ##, and even macro overloading. You can also redefine operators and special characters except quotes. A definition can extend to multiple lines by using the colon as a line separator. A $MACRO directive is global if it preceeds any $INCLUDE directives. ie. the included files have access to those Macro definitions. A $MACRO directive only affects the module level (ie. the current file) if used in an $INCLUDE file. So if A depends on B and B has some $MACRO directives, then those $MACRO directives only affect B and A has no access to them unless redeclared in module A.
  Notes:
  If you use the $MACRO directive, you are forcing Rapid-Q to preprocess your code, which will prolong the compilation process. Rapid-Q normally performs a single-pass compilation process.
  Usage:
  $MACRO ~ ,
  This redefines the comma character
  Try: ? STRING$(10 ~ "A")
  $MACRO strcat(a,b) a=a+b
  Implements a STRCAT function
  strcat(a$,"abc") translates to a$=a$+"abc"
  $MACRO VARID(x) V##x
  An example of token pasting
  DEFINT VARID(1) translates to DEFINT V1
  $MACRO TWO_PI (2*PI)
  $MACRO PI 3.14159
  Embedded Macros (forward only).
  Can't embed itself as a parameter.
  This avoids rescanning & recursion.
  $MACRO ADD(a,b,c,d) ADD(a,b)+ADD(c,d)
  $MACRO ADD(x,y) x+y
  $MACRO ADD(x,y,z) x+y+z
  An example of macro overloading

  3.2 Variables and Assignments
  Variables are stored in main memory, and stay there for the entire duration of your program. In Rapid-Q, type checking is very relaxed. Which means you can assign a string to an integer variable. The result is undefined, but will most likely return 0. Same goes with assigning a number to a string variable, the result is an empty string. Type checking is really done at the interpreter level in Rapid-Q, but since you don't want error messages popping up everywhere, I have disabled the check entirely. What this ultimately means is that you should be very very careful in assigning values to your variables, since you won't get any warnings from Rapid-Q. The only strict type checking done is for QObjects. You cannot assign a number or string to a variable expecting an Object for its value. Some examples of valid assignments:

               A% = "Hello" > "World"
               A$ = "Hi World!"
               A# = 34 + 34 - 324 * 3 / (34 / 5 + 5)

  If you've never programmed in BASIC before, you're probably wondering what all those symbols after the A mean. Well, since most implementations of BASIC does not restrict you to define your variables before you use them, you can define them by using these symbols:

               ?, ??, ???, %, &, !, #, $

  They represent BYTE, WORD, DWORD, SHORT, LONG or INTEGER, SINGLE, DOUBLE, and STRING, respectively. Of course, if you didn't put any symbol in front of your undeclared variable, it's automatically assumed that the variable is a DOUBLE. That is the implementation used in Rapid-Q, for other languagues, the default maybe SINGLE, LONG, or what have you. Here's a table for your viewing pleasure:

          Type       ID  Size  Range
          --------- ---- ---- -------------
          Byte        ?   1   0..255
          Word       ??   2   0..65535
          Dword     ???   4   Only Linux version for now...
          Short       %   2   -32768..32767
          Integer     &   4   -2147483648..2147483647
          Long        &   4   -2147483648..2147483647
          Single      !   4   1.5 x 1045..3.4 x 1038
          Double      #   8   5.0 x 10324..1.7 x 10308

  If you didn't like the way that was done, you could also use DIM to declare your variables, like so:

                  DIM Number AS INTEGER
                  DIM S AS STRING
                  DIM B AS BYTE

  Well, you get the idea. If you turned $TYPECHECK ON, then you will be forced to declare your variables like that. It's a nice habit to pick up, especially if you wanted to switch to languages like C or Pascal. You will be forced to declare all your variables before you use them. Here's something that's valid in Rapid-Q, but can confuse the daylights out of people:

                  DIM Num$ AS INTEGER

  Yes, try to avoid obfuscated code like that.
  3.3 Rapid-Q Components/Objects
  Rapid-Q offers reuseable components (or objects) which assists the programmer in developing Windows applications. Most RAD (Rapid Application Development) Programming languages offer this. For Visual C++, it's MFC, and for Java, it's JFC Swing. So what are visual components? They're basically just wrapper code that implement all the features of the Windows API control (or under Linux, whatever GUI API you're using) without all the headaches involved in using the API directly. For example, you can create windows using pure Windows API calls only, but this can run down for pages. In Rapid-Q, all this has been wrapped up into a component called QFORM. So instead of having to first register your class window, then display it and handle all the callbacks, all you do in Rapid-Q is:

                   DIM Form AS QFORM
                   Form.ShowModal

  Comparing this to a C/C++ program, it's much cleaner, and easier to understand. There are a lot of supported components in Rapid-Q, like QBUTTON, QIMAGE, QFILESTREAM, etc. There are also some which aren't supported, that's the restriction involved in using Rapid-Q. Components are created exactly the same way you create variables, by using DIM. Each component has its own properties, methods and events. Properties are like the component's attributes. For example, Left, Top, Width, and Height are properties common to all visible controls, which define its placement within the form or Window. Caption is a property of type STRING. For a QFORM component, the Caption property defines the title of that form. Caption for a QBUTTON defines the text of that button. Caption for something like QFILESTREAM does not exist, since a QFILESTREAM isn't a visible component. It has its own properties. For a complete guide of the properties, methods and events for all components, please check the Appendix section. Here's a quick example of how you can assign properties to your components:

                       DIM Form AS QFORM
                       Form.Caption = "My Application"
                       Form.Left = 100
                       Form.Top = 100

  Becareful to know which properties are Read-Only, and which ones are Write-Only. An example of a read-only property is the ITEMCOUNT property of a QLISTBOX. An example if a write-only property is the ICON property of a QFORM, used to specify the location of an icon to use as the default. Reading the Write-Only values, or Writing to Read-Only values have no defined meaning, and may result in a compile error or more seriously, your program crashing.
  3.4 Component Methods & Events
  Well, we've covered only the properties so far, but methods aren't much different. What exactly is a method you ask? It's really just a SUBROUTINE or FUNCTION. It's called a method, because the SUBROUTINE or FUNCTION only refers to that component. This is harder to explain than to understand. Here's an example of a method:

                    DIM Form AS QFORM
                    Form.Center
                    Form.ShowModal

  We used 2 methods here, Center, and ShowModal. The Center method is a SUBROUTINE that accepts no parameters. What it does is center the form on your desktop. ShowModal is actually a FUNCTION, but we ignore the return value in this case. It's a method used to Display your form, and wait for the user to close it. Note: Unlike some BASIC implementations, a FUNCTION can be called like a SUBROUTINE in Rapid-Q, you just ignore the return value. This is similar to C/C++. Other methods that you see may require some extra parameters, and some even accept an infinite number of parameters. You can also write these in Rapid-Q yourself, but I'll cover that topic later. So basically, methods are functions which perform a specific task on that component. In our above example, we're centering the form, and then displaying it.
  All right, now what about events? Well, this can be a confusing subject if we were talking in terms of message passing and callbacks. Well, luckily, we can take a much higher level look at it. An Event occurs whenever something happens. This is very vague, something happening could be anything from time elasping, user clicking the mouse, user pressing a key, etc. Rapid-Q can't trap all these events, but the most important ones are. For example, if a user clicked on a button, you'd want to write some code to perform that task. We have to define a CALLBACK function to handle it. For each event which occurred, you want to direct that event to a subroutine you wrote to handle the event. Here's how:

             SUB ButtonClicked
                PRINT "Button was clicked"
             END SUB

             DIM Button AS QBUTTON
             DIM Form AS QFORM

             Button.Parent = Form            '' Property
             Button.OnClick = ButtonClicked  '' Event
             Form.ShowModal                  '' Method

  Seems easy enough right? It really is. Whenever an "OnClick" message/event occurs, the program jumps into your subroutine ButtonClicked and executes the code you have waiting in there. The above program is complete, so you can try it out yourself. For a list of all events that a particular component can receive, just look at the Appendix section.
  3.5 Rapid-Q Subroutines & Functions
  There are some GOTCHAS associated with Rapid-Q SUBs and FUNCTIONs. The first, and most important, is that all values passed are passed by VALUE (except for objects, variants, udts, and arrays). To pass a variable by reference, you need to prepend an @ symbol. The second catch is that only a maximum of 10 parameters can be accepted (except when calling an API function, then it's limited to 25). There's no difference in the way you create SUBs or FUNCTIONs in Rapid-Q (as compared to other BASIC languages like QBasic/PB):

          FUNCTION FindMax (X AS INTEGER, Y AS INTEGER) AS INTEGER
            IF X > Y THEN
              FindMax = X      '' Return value is X
            ELSE
              FindMax = Y      '' Return value is Y
            END IF
          END FUNCTION

  The above code is valid, as is the following:

          FUNCTION FindMax (X%, Y%) AS INTEGER
            IF X% > Y% THEN
              FindMax = X%      '' Return value is X
            ELSE
              FindMax = Y%      '' Return value is Y
            END IF
          END FUNCTION

  However, as you may notice, you can't have FindMax% without attaching an AS INTEGER to the end of the function. To pass a variable by reference, attach an @ symbol in front of your variable:

          SUB StrCat (Source AS STRING, Text AS STRING)
              Source = Source + Text
          END SUB

          A$ = "Hello"
          StrCat(@A$, " World!")
          PRINT A$                '-- Should print: Hello World!

  Or if you prefer, you can also attach a BYREF keyword in your parameter list like so:

          SUB StrCat (BYREF Source AS STRING, Text AS STRING)
              Source = Source + Text
          END SUB

          A$ = "Hello"
          StrCat(A$, " World!")
          PRINT A$                '-- Should print: Hello World!

  Yet another approach you can use instead (note that this is the "old" way, maintained for compatibility reasons):

          SUB Strcat (A$, B$)
             A$ = A$ + B$
          END SUB

          A$ = "Hello"
          Strcat(A$, " world!")
          A$ = STACK.STR(0)
          PRINT A$

  The stack contains an array of integers and strings, to access the correct parameter, you have to specify the number (from left to right). The first element being 0. You can also pass QObjects, but you can't use it as a return value.

          SUB (Button AS QButton)
              Button.Left = 100
          END SUB

  All components/QObjects are passed by reference.
  3.6 Rules of Scope
  Rapid-Q is not like BASIC in this case. Since Rapid-Q is a simple top-down one-pass compiler, the scope is very similar to that of Pascal. Here's what I mean:

             SUB Test
                DIM I AS INTEGER
                I = 100
                PRINT I
             END SUB

             DIM I AS INTEGER
             I = 10

             SUB Test2
               PRINT I
             END SUB

             Test    '' Call Subroutine
             Test2

  Here's how the scope works, for the SUB Test, the LOCAL variable I only extends down as far as the end of that SUB block. The variable I in the main program extends down all the way to the end of your program. That means SUB Test2 can use the global variable I because it's within its scope. You can also redeclare the variable I in SUB Test2, in which case the local I is used instead of the global I. Here's another situation to demonstrate the scope of variable names:

             DIM I AS INTEGER

             SUB Scope (I AS INTEGER)
               DIM I AS INTEGER
               PRINT I
             END SUB

             PRINT I

  In fact, the line DIM I AS INTEGER is a wasted statement, since the variable I is shadowed by the parameter name I. Rapid-Q will warn you about this, but won't error out.

  Prev Chapter | Contents | Next Chapter