gb_func::gb__build_program - Build and Tokenize Program using .gbf Data

Syntax

call "gb_func::gb__get_file","my.gbf",gb__gbf_data$,"",gb__err$"
call "gb_func::gb__build_program",gb__gbf_data$,"pro5cpl","bbx","", gb__err,gb__err$

Description

This routine is used to build and tokenize a program using data in the .gbf file.

This section describes the program format, tokenization, error handling, and compilation errors for the function used to build and tokenize the program using .gbf data.

Program Format

The program is generated in the following 12 steps:

  1. The header block identifies the program, the resource file used to create the program, and copyright information. An ENTER line is generated to allow a single string variable to be optionally passed to the program.

    For each of the following, code is generated only if the corresponding variable exists in the [Program] section of the .gbf file:

    • Generate copyright line based on the "Copyright" variable.

    • Generate memory check based on the "Pages" variable.

    • Generate prefix statement based on the "Prefix" variable.

    • Generate precision statement based on the "Precision" variable.

    • Generate gb__show_forms assignment based on the "Show Forms" variable:

    • Show Forms = 0 or None: Initially hide all forms.

    • Show Forms = 1 or First: Initially hide all forms except the first one.

    • Show Forms = 2 or All: Initially show all forms.

    rem ' Program Name: C:/basis/vpro5/gb/sample.src
    rem ' Resource File: sample.brc
    rem ' Generated by GUIBuilder (June 15, 1998 @ 13:08:39)
    rem ' Portions Copyright (C) 1997-1998 BASIS International Ltd.
    seterr gb__no_arg
    enter gb__arg$; gb__args=-1,gb__args=pos($0a$=fattr(gb__arg$,$$),1,0)
    gb__no_arg:
    seterr 0

  2. Merge gb_ini.cod (standard initialization block). This file is merged into the generated program immediately after the header block. It contains initialization code and a series of data management functions. The initialization code confirms that the program is running under an interpreter that will support its GUI features, then it sets GB__SYSGUI$ to the first SYSGUI device found in the config.bbx file and GB__SYSPRINT$ to the first SYSPRINT device (if any) found in the config.bbx file. GB__SYSGUI$ is opened on channel GB__SYSGUI; if no SYSGUI device is found, the program terminates. After this basic initialization, the resource file is opened, and all forms from it are displayed (some might be hidden, based on the setting of the gb__show_forms parameter from the .gbf file).

  3. Merge in the user-defined initialization code, from the [Init] section in the .gbf file. This will typically do things like DIM record structures, open files, and set global variables. If the program uses grid and/or tab controls, some setup is typically required and would also go in this section. If the program will be using the printer, you can open it here; the printer device is GB__SYSPRINT$ (which will be set to "" if no printer alias was found in config.bbx).

  4. Generate event loop based on [Event] blocks. The following is a sample of the generated event loop code.

    rem ' -------------------------------------------------------------
    rem ' Event Loop
    rem ' -------------------------------------------------------------
    gb__windows=3; rem ' includes child windows

    This tells us how many windows there are in total.

    Note gb__forms tells us the number of top-level windows.

    dim gb__closed[gb__windows]

    This simply tells us that all windows/forms are initially open.

    gb__eoj=0
    repeat
    readrecord(gb__sysgui,siz=gb__event,err=gb__event_loop_end)gb__event$

    The following code will retrieve the Notice string into gb__notice$, formatted with the appropriate template. The gb__notice$ variable is only meaningful when gb__event.code$="N":

    if gb__event.code$="N" then
    : gb__generic$=notice(gb__sysgui,gb__event.x%);
    : dim gb__notice$:noticetpl(gb__generic.objtype%,gb__event.flags%);
    : gb__notice$=gb__generic$

    The following block of code returns the window ID given the Event Context. The reverse function is also available -- to return the Context Number for a given window ID, use: gb__context=fngb__context("10.10")

    rem ' Get Window ID from Event Context
    gb__win_id$=fngb__win_id$(gb__event.context)
    if gb__win_id$=$$ then
    break 

    There will be one of these "while" blocks for each form or child window in the resource file. This is where we decide which event subroutine needs to be called. Note for "X" events, we also track the fact that the window has been closed; when all windows have been closed, the event loop terminates.

    rem ' Handle events for window ID 10
    while gb__win_id$="10"
    if gb__event.id=1 and gb__event.code$="B" then
    : gosub W10_C1_PUSH_BUTTON;
    : break
    if gb__event.id=1000 and gb__event.code$="f" and gb__event.flags=0 then
    gosub W10__C1000_LOST_FOCUS;
    break
    if gb__event.code$="X" then
    : gosub W10_WIN_CLOSE;
    : gb__closed[1]=1;
    : break
    break; rem ' catch unhandled events
    wend; rem ' End of window ID 10 

    When all windows are closed, the control variable 'gb__eoj' will evaluate to 1, causing the event loop to terminate. Note the developer has the option to force this condition (terminating the event loop) by setting gb__eoj=1 at any time.

    if !(gb__eoj) then
    : gb__eoj=1;
    : for gb__window=1 to gb__windows;
    : gb__eoj=(gb__eoj and gb__closed[gb__window]);
    : next gb__window
    The event loop terminates when gb__eoj is non-zero:
    until gb__eoj
    gb__event_loop_end: rem --------------------------------------- 

  5. Merge in user-defined code from .gbf [EOJ] block, if any. You would close files and do any other required cleanup here.

  6. Merge gb_eoj.cod (standard EOJ/cleanup block). Destroy all contexts (windows) and close gb__sysgui. This is the standard end-of-job routine. It removes all forms from the screen, closes SYSGUI, then stops or exits.

    rem gb_eoj.cod - GUIBuilder generated programs: standard EOJ code
    rem Copyright (C) 1998 BASIS International Ltd. All Rights Reserved.
    rem
    rem ***** P R O G R A M E X I T **************************************
    rem
    gb__eoj:
    if gb__forms and gb__sysgui then
    : for gb__temp=1 to gb__forms;
    : print (gb__sysgui)'context'(gb__form_context[gb__temp]),'destroy'(0);
    : next gb__temp
    if gb__sysgui then
    : close (gb__sysgui)
    if tcb(13) then
    : exit
    : else
    : stop

  7. Merge in gb_err.cod (standard error handler). The error routine displays a message indicating that a particular error occurred at some line number and gives the user the option to retry or end the program. You can insert your own error handler here.

    rem gb_err.cod - GUIBuilder generated programs: standard error handler
    rem Copyright (C) 1998 BASIS International Ltd. All Rights Reserved.
    rem
    rem ***** E R R O R H A N D L E R ************************************
    rem
    gb__err:
    gb__temp=msgbox(errmes(err)+" ("+str(err)+")"+
    : " occurred at line "+str(tcb(5))+
    : " in program "+pgm(-2),5+48,"Error handler")
    if gb__temp=4 then
    : retry
    : else
    : goto gb__eoj

  8. Merge in gb_esc.cod (standard escape handler). If the user presses the break key (Ctrl-C or Break), this routine displays a message indicating that an escape has been detected. The user is given the option to end the program or return to where the escape was detected to continue running the program.

    rem gb_esc.cod - GUIBuilder generated programs: standard escape handler
    rem Copyright (C) 1998 BASIS International Ltd. All Rights Reserved.
    rem
    rem ***** E S C A P E H A N D L E R ***********************************
    rem
    gb__esc:
    gb__temp=msgbox("An ESCAPE has been detected. Do you want to end "+
    : "this program?",4+32+256,"ESCAPE handler")
    if gb__temp=7 then
    : return
    : else
    : goto gb__eoj

  9. User-defined functions/subroutines defined in the .gbf file are merged into the generated program at this point. Each one will start with a simple comment block giving the subroutine/function name.

  10. The event-handler routines from the .gbf file are merged into the generated program at this point. Each one will start with a comment block giving the details of the window, control, and event for which this event handler was defined. The subroutine label and final RETURN statement are also generated; the body of the event handler code is merged in between the subroutine label and the RETURN statement.

  11. If there are any standard functions or subroutines that you typically include in all or most of your programs (for example, date formatting or editing), you should put them in this file. The contents of gb_std.cod are merged in to the end of all programs generated by GUIBuilder.

  12. Generate the "END" statement.

Tokenization

The generated program is tokenized with the tokenizer specified in the argument list (in this example, "pro5cpl"). The .gbf variable 'Remarks = [y|n]' is used to determine whether comments will appear in the tokenized file. Use 'Remarks = No' to cause remarks to be skipped. The default is 'Remarks = Yes'. The extension of the generated program will also be determined from the argument list; in this case, it's "bbx."

Error Handling

The following lists the errors listed in gb__err:

gb__err

Error Description

0

Success-no errors.

-1

COMMAND.COM Error: Tokenizer was unable to find workfile.

-2

COMMAND.COM Error: Tokenizer could not be found.

1..255

Unexpected error -- Visual PRO/5 ERR.

1000

Compilation errors reported in gb__err$.

1001

Program Name variable missing from .gbf file.

1002

Resource File variable missing from .gbf file.

1003

Unable to create work file.

1004

Unable to open resource file.

1010

Error detected within _qres::Enumerate_Res_Forms.

1011

Error detected within _qres::Enumerate_Res_Child_Windows.

1012

Error detected within _qres::Enumerate_Res_Controls.

pro5cpl Compilation Errors

If gb__err=1000, gb__err$ will list the compilation error(s) in the following format:

"type:c(1*=0),line:n(3*=0),msg:c(16*=0),arg1:c(8*=0),arg2:c(8*=0),arg3:c(8*=0)"

Each error will be reported in a string of this format, terminated by a linefeed. There will be one record for each error. The number of errors will be equal to: pos($0a$=gb__err$,1,0).

If type="f", the error was in an include file:

  • line = error line number within the include file, or 0 to indicate an error opening the file.

  • msg = text of error reported by the tokenizer or gb_func::gb__get_file.

  • arg1 = include file which caused the problem:

  • arg2 = ""

  • arg3 = ""

To retrieve the block of code (include file) with the error:

call "gb_func::gb__get_file",arg1$,gb__string$,gb__gbf_data$,gb__err$

If type="g", the error was in user-defined code in the gb__gbf_data$:

  • line = error line number within the .gbf code chunk.

  • msg = text of error reported by gb__bbxcpl$.

  • arg1 = First argument to be passed to fngb__get_code.

  • arg2 = Second argument to be passed to fngb__get_code.

  • arg3 = Third argument to be passed to fngb__get_code.

To retrieve the block of code with the error:

n = fngb__get_code(arg1,arg2,arg3,gb__gbf_data$)
gb__sub_name$ is returned as the name of the event-handler subroutine.
gb__sub_code$ is returned as the body of the event-handler subroutine.

If type="i", the error was in internal (generated) code:

  • line = error line number within the generated program source file.

  • msg = text of error reported by the tokenizer.

  • arg1 = ""

  • arg2 = ""

  • arg3 = ""