Baumeister Mediasoft Engineering BME - Baumeister Mediasoft Engineering  Data Types and Definitions - English Version Datentypen und Definitionen - Deutsche Version
Baumeister Mediasoft Engineering
Bartels AutoEngineerCarLogServicesResourcesCompany ProfileContact Us
Baumeister Mediasoft Engineering » Bartels AutoEngineer » BAE Documentation » User Language Programmer's Guide » Language Description » Data Types and Definitions
Bartels User Language - Programmer's Guide

2.3 Data Types and Definitions

Bartels AutoEngineer® Documentation

2.3.1 Data Types

Bartels User Language provides the following basic data types:

char Character taken from the machine's character set
int Numeric integer value
doubleNumeric double precision floating point value
stringCharacter array
index Index to predefined BAE DDB structure

Bartels User Language provides the following combined data types:

arrayCollection of elements with same data type
structCollection of elements with different data types

Data Type Conversion

Some operators can cause implicit data type conversions. A series of arithmetic operations require operand(s) with special data types. Likewise a corresponding data type compatibility is required with the assignment of values to variables and/or the passing of function parameters. The User Language Compiler checks the compatibility of the operands. Operands of different data types are automatically casted to a common or valid data type if possible. These type casts are applied according to the following rules: valid type conversions without loss of information are char to int, char to string and int to double; permissible type casts with a loss of information are int to char and double to int. The User Language Compiler issues error messages if the required type compatibility can not be achieved by applying the type cast rules.


2.3.2 Variables

All global and local variables must be declared before use. A variable declaration defines the name and the data type of the variable. Such declarations determine, how user-introduced names are to be interpreted by the User Language. Each declaration consists of a data type specification and a list of declarators. Each declarator is composed of the corresponding variable name and an optional initialization.

Basic Data Types

The declaration of char variables is applied as in

char c;
char TAB = '\t', NEWLINE = '\n';

where the char variables c (not initialized), TAB (initialized with the tabulator control character) and NEWLINE (initialized with the newline control character) are declared.

The declaration of int variables is applied as in

int i, MAXLINELEN = 80;
int pincount = 0;

where the int variables i (not initialized), MAXLINELEN (initialized with the value 80) and pincount (initialized with 0) are declared.

The declaration of double variables is applied as in

double x_coord, y_coord;
double MMTOINCH = 1.0/25.4;
double starttime = clock();

where the double variables x_coord and y_coord (not initialized), MMTOINCH (initialized with a numeric expression) and starttime are declared; the variable starttime is initialized with the return value of the system function clock (i.e., the elapsed CPU time).

The declaration of string variables is applied as in

string s1;
string ProgName = "TESTPROGRAM", ProgVer = "V1.0";
string ProgHeader = ProgName+"\t"+ProgVer;

where the string variables s1 (not initialized), ProgName (initialized with TESTPROGRAM), ProgVer (initialized with V1.0) and ProgHeader are declared; ProgHeader is initialized with an expression which emerges from a catenation of the string variable ProgName, the tabulator control character and the string variable ProgVer.

The declaration of index type variables is applied as in

index L_MACRO macro;
index L_CNET net1, net2;

where the index variables macro (index variable type L_MACRO), net1 and net2 (index variable type L_CNET) are declared. The declaration of index variable types consists of the keyword index followed by the name of the index variable type (e.g., L_MACRO and/or L_CNET) and the desired variable name(s). The identifiers of the index variable types are predefined (see also appendix B of this manual). Only index variable types compatible to each other can be used in the same program. The reason for this restriction is, that with index data types the access to corresponding entries of the Bartels AutoEngineer design data base (DDB) is defined; the availability of these DDB entries differs according to the interpreter environment (i.e., the Schematic Editor provides data type definitions which are not available in the layout system). The User Language Compiler issues an error message if incompatible index variable types are used in the same program. The User Language Interpreter behaves similarly; an error message is issued and the program is canceled when trying to run a User Language program with references to index variable types not compatible with the current interpreter environment. Please refer to appendix A and/or appendix B of this manual for information about index data type compatibilities.


An array (or vector) is a complex data type composed of elements of the same data type. With the declaration of array variables the specification of the array dimension is required in addition to the data type and variable name definition. The dimension is specificied by appending bracket pairs to the variable name, with each bracket pair corresponding to one dimension. At the initialization of array variables, the corresponding values are to be separated by commas, and each array dimension is to be enclosed with braces.

The declaration of array variables is applied as in

int intary[], intfield[][][];
double valtab[][] = {
      { 1.0, 2.54, 3.14 },
      { 1.0/valtab[0][1], clock() }
string TECHNOLOGIES[] = {
      "TTL", "AC", "ACT", "ALS", "AS", "F",
      "H", "HC", "HCT", "HCU", "L", "LS", "S"

where the int arrays intary (1-dimensional) and intfield (3-dimensional), the 2-dimensional double array valtab and the 1-dimensional string array TECHNOLOGIES are declared. The declarations of valtab and TECHNOLOGIES contain initializations according to the following assignments:

valtab[0][0] = 1.0;
valtab[0][1] = 2.54;
valtab[0][2] = 3.14;
valtab[1][0] = 1.0/valtab[0][1];
valtab[1][1] = clock();

The basic User Language data type string is equivalent to a 1-dimensional char array, i.e., the declarations

string s;


char s[];

are synonymous.


A structure is a complex data type composed of elements with different data types, i.e., the elements of a structure are to be defined with different names. The purpose of structure definitions is to unite different variable types, which share special relations regarding on how they are to be processed. It has to be distinguished between structure definitions and structure declarations. A structure definition is composed of the keyword struct, the name of the structure definition and the list of structure element definitions (enclosed with braces). A structure declaration consists of the keyword struct, the name of a valid structure definition and the name of the variable to be associated with the structure definition. Structure definitions and structure declarations can be combined. The name of the structure definition can be omitted. Initializations in structure declarations are allowed in which case the syntax corresponds to the array declaration conventions (see above).

The declaration of structures is applied as in

// Structure declarations

struct coordpair {
      double x
      double y;

struct coordpair elementsize = {

struct elementdes {
      string fname, ename;
      int class;
      struct coordpair origin, size;
      } element = {

struct {
      string id, version;
      struct {
              int day;
              string month;
              int year;
              } reldate;
      } program = {
              "UL PROGRAM",
              "Version 1.1",
              { 4, "July", 1992 }

where the definition of the structure coordpair, the declaration of the variable elementsize (structure of type coordpair), the definition of the structure elementdes, the declaration of the variable element (structure of type elementdes) and the declaration of the struct variable program is accomplished. The declarations of elementsize, element and program contain initializations according to the following assignments:

element.size=plansize;"UL PROG";
program.version="Version 1.1";;

The following example illustrates how structure and array definitions and/or declarations can be combined:

struct drilldef {
      index L_DRILL drilltool;
      struct { double x, y; } drillcoords[];
      } drilltable[];

Data Type Renaming

Bartels User Language provides a mechanism for renaming data types. This feature allocates an additional name for an already known data type (but it does not create a new data type). Data type renaming is accomplished by the specification of the keyword typedef followed by a valid data type specification and the new name to be introduced for this data type. A data type specification introduced with typedef can subsequently be used as data type specifier when declaring variables, functions or function parameters.

Data type renaming is utilized as in

typedef index L_CNET NETLIST[];
typedef int IARY[];
typedef IARY MAT_2[];
typedef struct {
      int pointcount;
      struct {
              int t;
              double x,y;
              } pointlist[];
      } POLYLIST[];
MAT_2 routmatrix;
NETLIST netlist;
POLYLIST polygonlist;

where the variables routmatrix (2-dimensional int array), netlist (1-dimensional index array of type L_CNET) and polygonlist (1-dimensional array of structures containing an int element and a struct array) are declared.


2.3.3 Functions

A function usually is defined for solving a certain sub-problem derived from larger problems. The use of functions can simplify the process of software maintenance considerably since complex operation sequences can be applied repeatedely without the having to code the corresponding instructions time and again. Bartels User Language distinguishes between the predefined system functions and the user-defined functions.

Function Definition

The Bartels User Language system functions are known to the User Language Compiler, and they are bound to the User Language Interpreter. See appendix C of this manual for the description of the Bartels User Language system functions. The programmer can make use of the system functions or write his own functions.

A function definition consists of the function header and the function block. The function header is composed of the function type specification, the function name, and the definition and declaration of the function parameters. The function type determines the data type of the value to be returned by the function. The void function type applies to functions without return value. The function data type defaults to int if the function type specification is omitted. The function type is followed by the function name, which must be unique throughout the program text. The function parameter definition consists of the list of the function parameter names and/or declarations (separated by commas); the function parameter list must be enclosed by parentheses. All function parameters - except for the int parameters and those already explicitly declared with the parameter list - must be declared at the end of the function header, with the declaration of the parameters corresponding to the declaration of normal variables (see above). The function header is followed by the function block. The function block must be enclosed by braces, and consists of the statements to be executed by the function.

Function definition examples:

double netroutwidth(index L_CNET net)
// Get the routing width of a given net
// Returns : width or 0.0 if two pins with different width
      index L_CPIN pin;       // Pin index
      int pincnt=0;           // Pin count
      double rw=0.0;          // Rout width
      // Loop through all pins
      forall (pin of net) {
              // Test if the pin introduces a new rout width
              if (pin.RWIDTH!=rw && pincnt++>0)
              // Set the rout width
      // Return the rout width

int allpartsplaced()
// Test if all net list parts are placed
// Returns : 1 if all parts are placed or zero otherwise
      index L_CPART cpart;    // Connection part index
      // Loop through the connection part list
      forall (cpart where !cpart.USED)
              // Unplaced part matched
      // All parts are placed

double getdistance(xs,ys,xe,ye)
// Get the distance between two points
// Returns : the distance length value
double xs, ys;                // Start point coordinate
double xe, ye;                // End point coordinate
      double xd=xe-xs;        // X distance
      double yd=ye-ys;        // Y distance
      // Calculate and return the distance (Pythagoras)

double arclength(r,a1,a2)
// Get arc segment length by radius and start-/end-point angle
// Returns : the arc segment length value
double r;                     // Radius
double a1;                    // Start point angle (in radians)
double a2;                    // End point angle (in radians)
      // Arc; "absolute" angle between start and end point
      double arc = a1<a2 ? a2-a1 : 2*PI()+a2-a1;
      // Get and return the arc segment length

double getangle(cx,cy,x,y)
// Get the angle of a circle arc point
// Returns : the angle (in radians; range [0,2*PI])
double cx, cy;                // Circle center coordinate
double x, y;                  // Circle arc point coordinate
      double res;             // Result value
      // Get arc tangent of angle defined by circle point
      // Test the result
      if (res<0.0)
              // Get the "absolute" angle value
      // Return the result value

double PI()
// Returns the value of PI in radians
      // Convert 180 degree and return the result

void cputimeuse(rn,st)
// Report CPU time usage (in seconds)
string rn;                    // Routine name
double st;                    // Start time
      // Print CPU time elapsed since start time
      printf("(%s) Elapsed CPU Time = %6.1f [Sec]\n",rn,clock()-st);

Function Call and Parameter Value Passing

Each function known in a User Language program and/or program module can be called in this program and/or program module. However, only system functions compatible to each other can be used in the same program. The reason for this restriction is, that a system function is implemented and/or available in a certain set of interpreter environments only (e.g., the system function for setting CAM Processor plot parameters obviously can not be called from the Schematic Editor). The User Language Compiler issues an error message if incompatible system functions are used in a program. The User Language Interpreter behaves similarly; an error message is issued and the program is canceled when trying to run a User Language program with references to system functions not compatible to the current interpreter environment. Please refer to appendix A and/or appendix C of this manual for information about system function compatibilities.

A function call consists of the function name and - enclosed with parentheses - the list of the parameters (arguments) to be passed to the function.

The contents of global program variables are available in each function of the same scope. I.e., global variables can be used at any time for passing values to functions. Besides that values can be passed with the function parameters. Since the usage of parameters provides easy maintenance, this method should be preferred. The list of parameters which is passed to the function must correspond with the formal parameter list introduced with the function definition (i.e., the parameter count as well as the data types must match). At the function call, the values of the current parameters are copied to the corresponding formal parameters. After successful execution of the function, each parameter value changed by the function is stored back to the current parameter (this applies only if the parameter refers to a variable). Finally, there is the possibility of passing values with the function return value, where the return statement is used for setting a function result value which is passed back to the caller of the function and can be evaluated in the expression containing the function call.

Examples for function calls and value passing:

// Date structure
struct date { int day, month, year; };
// Global program variables
string globalstr="Global string";
int fctcallcount=0;

// Main program
      // Local variables of main
      string resultstr="function not yet called";
      struct date today = { 0, 0, 0 };
      double p=0.0, b=2.0, e=10.0;
      // Print the global variables
      printf("fctcallcount=%d, %s\n",fctcallcount,globalstr);
      // Print the local variables
      printf("today : %d,%d,%d",,today.month,today.year);
      printf("\t\tb=%.1f, e=%.1f, p=%.1f\n",b,e,p);
      // Call function
      // Print the global variables
      printf("fctcallcount=%d, %s\n",fctcallcount,globalstr);
      // Print the local variables
      printf("today : %d,%d,%d",,today.month,today.year);
      printf("\t\tb=%.1f, e=%.1f, p=%.1f\n",b,e,p);

string function(curdate,base,exponent,power)
struct date curdate;          // Current date parameter
double base;                  // Base parameter
double exponent;              // Exponent parameter
double power;                 // Power parameter
      // Increment the function call count
      // Set the global string
      globalstr="Global string changed by function";
      // Get the current date
      // Calculate the power
      // Return with a result string
      return("function result string");

The example above produces the following output:

fctcallcount=0, Global string
resultstr="function not yet called"
today : 0,0,0         b=2.0, e=10.0, p=0.0
fctcallcount=1, Global string changed by function
resultstr="function result string"
today : 4,6,92                b=2.0, e=10.0, p=1024.0

Control Flow and Program Structure

After calling a function, this function keeps control of the program flow until it meets with another function call or a return statement or else has reached its end after processing its last statement. At a function call the control is passed to the called function. When reaching a return statement or the end of the function, the control is passed back to the caller of the function. If a function with the name main is defined in a program, the User Language Compiler produces machine code for calling this function immediately after initializing the global program variables. I.e., the program control flow usually starts with the main function. Since each function passes the control back to the caller (unless the program contains endless recursions), the control will finally fall back to the main function. If the end of the main function is encountered or if a return statement is reached in the main function, then the end of the program is reached and the control is passed back to the User Language Interpreter, which then terminates the program flow.

Recursive Functions

Functions can be used recursively, i.e., a function can call itself directly or indirectly. This however is meaningful only if with each recursive function call a condition changes in order to reach a clearly defined final state, which causes a recursion interrupt (otherwise the function is endless-recursive and the program runs "forever").

Recursive programming of functions can save program code and increase the legibility of the source code. However, program runtime and memory requirements increase with recursive programming and endless recursions might be implemented inadvertently. Hence careful considerations should be taken on the use of recursive functions. The Bartels User Language Interpreter eventually encounters an out of memory and/or stack overflow error when processing endless recursive functions since at least a return address must be stored for each function call.


2.3.4 Scope Rules

The User Language Compiler checks the validity of each object reference (name and/or identifier) of the program to be compiled. For that purpose a valid program scope is assigned to each identifier used in the program. This (lexical) identifier scope is the region of the program text where the identifier is defined. he corresponding object is known and can be referenced throughout this scope. There is a distinction between global and local scopes. The global scope extends to the entire program (i.e., separately compiled program modules and/or libraries to be linked later), whilst local scopes correspond with the function definitions.

The function names of a program are global, i.e., they are valid throughout the entire program. Variable and type names defined inside a function are local to this function; variable and type names defined outside any function are global. Function parameter names are treated like local variable names, i.e., they are local to the corresponding function. Structure definition names on principle are global throughout the currently compiled program text. Function and global variable scopes can be restricted to the currently compiled program text by assigning the static storage class. The static storage class is used to avoid name conflicts when binding and/or linking different program modules and/or libraries.

To avoid name conflicts, the elements of each object class must have different names inside their corresponding valid scopes. Local object references have higher priority than global object references.

Baumeister Mediasoft Engineering » Bartels AutoEngineer » BAE Documentation » User Language Programmer's Guide » Language Description » Data Types and Definitions

Data Types and Definitions • © 1985-2018 Oliver Bartels F+E • Updated: 04 April 2011, 11:03 [UTC]

Baumeister Mediasoft Engineering, Clontarf, Dublin 3, D03 HA22, Ireland
© 2018 Manfred Baumeister

Data Types and Definitions - English Version Datentypen und Definitionen - Deutsche Version