[SparForte][Banner]
[Top Main Menu] Intro | Tutorials | Reference | Packages | Examples | Contributors   [Back Page]      [Next Page]  

Block Statements and Subprograms

SparForte scripts can be organized using declare blocks, procedures and functions. This enables pieces of a program to be easily reused. A procedure is a routine that can be called but returns no value. For example, put_line is a procedure. A function always returns a value so it can be used as part of an expression. strings.length is an example of a function which responds with the length of a string.

Overall Structure

An AdaScript script consists of a sequence of executable statements. These statements can appear as a simple list or can be enclosed in a "library" unit. The basic library unit is a main procedure (or sometimes called a main program or main subprogram). Other library units may be introduced in the future (such as packages).

If pragma ada_95 is used, the statements must be enclosed in a library unit.

Some features may not be available with a simple list of statements.

Declare Block

Declare blocks (also called block statements) contains a sequence of statements or commands that can include locally declared variables. Declare blocks are located in the executable part of a script. Between declare and begin, declarations can be made. Between begin and end are executable statements. The declarations are visible to these executable statements.

A new block can be created without declaration any variables by using begin...end without the declare section.

declare
   i : integer := 5;
begin
   ? i;
end;
 

Example: The Declare Block Statement

Procedure and Function Blocks

Repeatable blocks of a series of instructions (like Perl sub or Python def) can be created with the word procedure or function.  A procedure is a set of instructions with a name.  A function is a set of instructions with a name that computes and returns a value and can be used in an expression.  Like a declare block, local variables can be declared before the word begin. Procedure and function subprograms must finish with end and the name of the subprogram: this is to clarify the structure of the program.

Ada: In Ada, the name of the subprogram is optional after end. In AdaScript, the name is required.

procedure print_title is
begin
   put_line( "Script to Process New Orders" );
   new_line;
end print_title;
 

Example: The Procedure Subprogram Statement

Procedures and functions may be nested: you can declare them in the declaration parts of another procedure, function or declare block. These nested subprograms only exist for the scope of this parent block.

A procedure may be terminated early using a return statement. A function uses return to return back a value.

Ada: AdaScript doesn't support creating new arithmetic operators by defining functions with operator symbols.

Procedure and Function Parameters

Both procedures and functions can have parameters.  If a procedure or function has no parameters, do not include any parantheses. If there are parameters, they are listed with a name, a mode and a type. By default, all parameters are "in" mode parameters: they give additional information to a subprogram and are treated as constants.  The word "in" is optional before the type of parameter.

function add_two( number : integer ) return integer is
begin
  return number+2;
end add_two;

 

Example: The Function Subprogram Statement

Besides in mode parameters, parameters may also be out or in out mode. Out parameters return values, and in out read, modify and return values. These parameters may refer to arrays, records, array elements or record fields, in addition to the scalar types.

Functions are not allowed to use out parameters.

Ada: Ada does not permit functions to use in out mode parameters.

Procedures and functions can only declared inside the declaration section of a script's main procedure block (or declared nested inside other subprograms or declare blocks).

procedure my_script is
procedure my_proc is -- OK
...
end my_script;
 

Example: A Main Program Procedure

That is, they must be in a script that has a main procedure block.

i : integer;
i := 5;
procedure my_proc is -- BAD...use a main procedure block
...

The built-in procedures and functions found in the SparForte packages may include parameters with other modes. in out mode means the value of the parameter is used by the subprogram and may be changed. out mode means the parameter is not read by the subprogram but a value will be returned using the parameter. Functions may only use in mode. The modes are described on the front page of the Packages section of this documentation.

Ada: access mode parameters are not supported for user-defined subprograms. Named parameters are not supported. Default values are not supported.

Forward Subprograms and Recursion

Forward declarations and recursion are planned but not yet implemented.

Separate Subprograms

Procedures and functions maybe loaded from a separate file. (This is referred to as a "subunit": a feature of a script stored in a separate file).

Copy your subprogram (or create a new one) and put it in a file with the name of the subprogram. For example, if you have a separate procedure called "t2", put it in a file called "t2.sp". The filename must match the name of the subprogram.

Separate subprograms must begin with a separate statement as the first line in the file. This indicates that the file is not an executable script. The separate statement should include the name of the parent script. Each separate subprogram belongs to a single, specific parent script.

-- t2.sp is a separate procedure
separate( t );
procedure t2 is
begin
  put_line( "t2 was called!" );
end t2;
 

Example: t2.sp is a loadable by a script named t.sp

In the parent script (the one that will load the subprogram), declare the subprogram but replace the body of the subprogram with the word separate.

procedure t is
  procedure t2 is separate;
begin
  t2;
end t;
 

Example: t.sp loads t2.sp and executes t2

SparForte will search for the separate subprogram using the SparForte library path. The path is specified using the -L command option or using the environment variable SPAR_LIBRARY_PATH. By default, SparForte will search the current directory. The separate subprogram must exist and be readable in order to load it.

In SparForte, procedures and functions can be nested. Support for separate nested subprograms is planned but not yet implemented.

Separate subprogram blocks are similar to include files in other languages except that the separate block is a part of a specific main script.

Ada: GCC Ada also has separate subunits. They are implemented in the same way.

Separate Declarations

A separate declaration file is the SparForte equivalent of an include file. It is an set of declaration statements stored in a separate file. The file can include variables, constants, types, functions, procedures, pragmas, etc. A declaration file is used to share common declarations across many scripts.

The separate declaration file is inserted into another script using "with separate". Since the declaration file is inserted, they have the same scope as the declaration block they are used in. Any subscript pragmas will also affect the file loading the declaration file. The with separate statement can occur in a declaration section of any block (a main procedure, procedures, functions or a declare block).

procedure main is
  with separate "globals.sp";
begin
  ? company_name; -- displays "PegaSoft"
end main;
 

Example: Loading a separate declaration file

Unlike separate procedures / functions, declaration files are not tied to a particular script. The subscript fragment must have "separate" as its first statement. This identifies it as a separate declaration file.

-- This is the file named globals.sp
separate;
company_name : constant string := "PegaSoft";
 

Example: A very short separate declaration file containing one constant

Like separate subprograms, SparForte will search for the declaration file using the SparForte library path. The path is specified using the -L command option or using the environment variable SPAR_LIBRARY_PATH. By default, SparForte will search the current directory. The declaration file must exist and be readable in order to load it.

The separate declaration file may contain more "with separate" statements. If the same file is included twice in the same scope, duplicate declaration errors will occur. Having a file include itself, or having a nested with separate include the file, will result in a loop and SparForte will report an error.

Subscripts are loaded before a script starts execution. If you do something unusual such as to create a for loop containing a declare block with a "with separate", the with separate only executes once. However, the subprograms contained in the separate declaration file will access the new variable values as the for loop iterates, just as if they were declared without the with separate.

Subscripts are permitted with pragma ada_95, even though they are not a part of the Ada 95 standard, to allow large scripts to be broken up.

Subscripts are permitted in a restricted shell to allow large scripts to be broken up.

Implementation Note: with separate has a string literal as a parameter. Because the separate file is loaded before the program is running, any variables that might contain the file path cannot exist when the file is loaded. So you're stuck with a string literal.

Rationale: Subscripts are intended as a simple mechanism to break up large scripts until loadable user-defined packages are completed.

Exceptions

Procedures, functions, declare blocks or main programs can have an exception handler. If an error or exception occurs, you can detect it and perform remedial action in the handler.

Declaring Exceptions

Exceptions can be declared by creating variables with the type of exception. They are not intended for reporting all errors, but errors that are rare or inconvenient to test for in the middle of a routine.

file_load_error : exception;
 

Example: An exception declaration

The execption type name may be followed with a "with/use". with specifies a default message to accompany the exception error message. use specifies a status code to return if the exception is raised to the main program and is not handled.

file_load_error : exception with "unable to load the file" use 15;
 

Example: An exception declaration with a with/use clause

The with/use clause is not available with pragma ada_95.

Unlike other variables, two exceptions with the same name declared in overlapping scopes are not allowed. This is to make it easier to identify which exception was raised. For example, if you had a global exception named "disk_space_error" you cannot declare another "disk_space_error" in a procedure.

Ada: Ada permits exceptions with the same name in overlapping scopes. It differentiates between them with dotted notation.

Exception Handlers

Exception handlers are created using an exception section. Once an exception handle runs, control is not returned to the block where the exception occurred: the exception handler replaces the remainder of the executable statements in the block.

An exception handler is similar to a case statement. when sections contain the executble code to run in the case of a specific exception.

If there is a when others section, it will run if none of the preceeding sections applied. when others will also handle most run-time errors.

procedure divide( x : integer; y : integer ) is
begin
  put_line( x / y );
exception when others =>
  put_line( "undefined" );
end divide;
 

Example: Math errors like dividing by zero display "undefined"

Errors that occur during the syntax check when a program starts cannot be handled as the program is not running yet. A small number of errors, such as exceeding the number of variables the language can declare, cannot be handled, mainly because the run-time system is in a corrupted or uncertain state.

If an exception handler occurs in a function, a function return can be placed in the handler.

If a block has no exception handler, the enclosing blocks will be searched for a handler. (That is, the exception will propogate.)

An exception handler can contain a declare/begin block with its own exception handlers.

Re-raising Exceptions

The raise command will propogate the exception after handling. That is, it will reinstate the exception to exception handlers in the surrounding blocks, just as if the exception was not handled.

procedure main_prog is
 
  procedure divide( x : integer; y : integer ) is
  begin
    put_line( x / y );
  exception when others =>
    put_line( "undefined" );
    raise;
  end divide;
 
begin
  ? divide( 2, 0 );
exception when others =>
  put_line( standard_error, "an exception occurred" );
end main_prog;
 

Example: Both exception handlers will run

Raising New Exceptions

The raise command will raise user-declared exceptions. An alternate message can be given with a with clause.

raise file_load_error with "the customer file did not load";
...
exception when some_other_exception =>
  null; -- do something here
when file_load_error =>
  null; -- do something here
when others =>
  put_line( standard_error, "an unexpected exception occurred" );
 

Example: Raising and handling a user exception

raise can be used within an exception handler to raise a different exception.

The with clause is not allowed with pragma ada_95.

Profile Files

When SparForte is used as a login shell, it checks for the existence of two files: "/etc/sparforte_profile" and ".sparforte_profile" in the user's home directory. The first is a system-wide initialization file. The second is for initializing personal preferences. The personal file always run after the system-wide file. These are only read on login, or if SparForte simulates a login when it is started with --login.

SparForte checks these files before opening them. They must meet the following conditions:

  • They must be regular files (that is, not a directory or other special-purpose file)
  • The file permissions must allow the files to be read by the user
  • The file permissions must not allow others to write to the files (for security purposes)
  • They must not be empty

If a profile exists but doesn't meet these conditions, an error is reported and the profile file will not be run. The login session will be aborted.

Policies and the Global Policy File

A policy is a special block. It contains a collection of pragmas that apply to a project. It may also contain static if or case statements (that is, with expressions that can be evaluated before the program is run) so that different pragmas can be applied in different situations. They are intended for use by architects.

Policy blocks are named so that each block can be applied only once. An identifier already declared error will occur if the same block is applied twice.

A policy block should appear before the main program.

policy web_app_policy is
  pragma ada_95;
  if not System.Development_Phase then
    pragma restriction( no_external_commands );
  end if;
end web_app_policy;
 

Example: A Simple Policy Block

There can also be a global policy file. When SparForte runs a script, it searches for a file called /etc/sparforte_policy. This is a system-wide initialization file, similar to a profile file. It's purpose is to setup any architectural pragmas common to all scripts on a server. The policy file is not executed for interactive sessions. The file is indended to be used by architects who maintain the standards and integration of different computer systems, separating their concerns from those of the programmers.

SparForte checks this file before opening it. It must meet the following conditions:

  • It must be a regular file (that is, not a directory or other special-purpose file)
  • The file permissions must allow the file to be read by the user
  • The file permissions must not allow others to write to the file (for security purposes)
  • It must not be empty

If a policy file exists but doesn't meet these conditions, an error is reported and the file will not be run. The script will be aborted.

A policy file may only contain pragma's. It cannot contain include files.

Configuration Blocks and Global Configuration File

A configuration block is a special block. It contains a collection of declarations and pragmas at apply to a project. These are for describing environment settings such as server names, login credentials for services (such as databases) and so forth. The block is intended for use by system administrators.

Configuration blocks are named so that each block can be applied only once. An identifier already declared error will occur if the same block is applied twice.

A configuration block should appear before the main program.

There can also be a global configuration file. After running any global policy file, SparForte searches for a file called . This is a system-wide initialization file containing a configuration block. The configuration file is not executed for interactive sessions. The file is intended to be used by system administrators who must maintain different enviroments, separating their concerns from those of the programmers.

SparForte checks this file before opening it. It must meet the following conditions:

  • It must be a regular file (that is, not a directory or other special-purpose file)
  • The file permissions must allow the file to be read by the user
  • The file permissions must not allow others to write to the file (for security purposes)
  • It must not be empty

If a configuration file exists but doesn't meet these conditions, an error is reported and the file will not be run. The script will be aborted.

A configuration file may only contain declarations. That is, it may contain variable declarations, constant declarations, type declarations, pragmas, function declarations or procedure declarations—anything which can be created in the declaration section of a subprogram. However, the content is mostly likely to be a group of constants. It cannot contain include files.

-- Database settings for this server
configuration dev_environment is
  db_host : constant string := "db1.ourcompany.com";
  db_username : constant string := "webapp";
  db_password : constant string := "secret";
end dev_environment;
 

Example: A Simple /etc/sparforte_config File

SparForte will not report an error if there are any unused variables from the configuration file. It is assumed that some declarations will not be used in some scripts.


 
[Right Submenu]

 AdaScript versus GCC

 Case Sensitivity

 Reserved Words

 Comments

 Literals

 Bourne Shell Word Expansions

 Fundamental Types

 User-defined Types

 Enumerated Types

 Arrays

 Records

 Basic Assignment

 The @ and % Operands

 Command Argument Shortcuts

 Redirection and Pipelines

 Command Line Interaction

 Built-in Shell Commands

 The Current Directory

 Database Commands

 Flow of Control

 Other Statements/ Subprograms

 External Commands

 Block Statements and Subprograms

 TCP/IP Sockets

 Numeric Formatting with Put

 Interpreter Directives

 Command Line Options

 Command Reference

 ASCII and Latin_1 Character Sets

 Common Error Messages

 Common PHP Functions and the SparForte Equivalent

[Back to Top] Back To Top [Small Forte Symbol]