Baci Pas
Baci Pas
November 5, 2002
BACI Pascal Compiler User’s Guide 1
Contents
1 Introduction 2
3 Concurrency Constructs 4
3.1 COBEGIN—COEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3.2 Semaphores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3.2.1 Initializing a Semaphore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3.2.2 P (or WAIT) and V (or SIGNAL) Procedures . . . . . . . . . . . . . . . . . . . . . . . 5
3.2.3 Examples of Semaphore Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.3 Monitors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.3.1 Condition Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.3.2 WAITC and SIGNALC Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.3.3 Immediate Resumption Requirement . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.3.4 An Example of a Monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.4 Other Concurrency Constructs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.4.1 ATOMIC Keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.4.2 PROCEDURE suspend; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.4.3 PROCEDURE revive( process number : INTEGER); . . . . . . . . . . . . . . . 9
3.4.4 FUNCTION which proc : INTEGER; . . . . . . . . . . . . . . . . . . . . . . . . 9
3.4.5 FUNCTION random( range : INTEGER ): INTEGER; . . . . . . . . . . . . . . 9
1 Introduction
The purpose of this document is to provide a brief description of the BACI Pascal Compiler and Concur-
rent PCODE Interpreter programs and a description of how to use them. The compiler first compiles the
user’s program into an intermediate object code called PCODE, which the interpreter then executes. The
Pascal compiler supports binary and counting semaphores and Hoare monitors. The interpreter simulates
concurrent process execution.
The compiler and interpreter originally were procedures in a program written by M. Ben-Ari, based
on the original Pascal compiler by Niklaus Wirth. The program source was included as an appendix in
Ben-Ari’s book, “Principles of Concurrent Programming”. The original version of the BACI compiler and
interpreter was created from that source code. Eventually, the compiler and interpreter were split into two
separate programs, and a C−− compiler was developed to compile source programs written in a restricted
dialect of C++ into PCODE object code executable by the interpreter.
The syntax for the Pascal compiler is explained below. This guide is applicable only to the BACI Pascal
compiler and not to the BACI C−− compiler. Users interested in the C−− compiler should consult its user
guide (see the file cmimi.ps).
2. There are no files other than input and output. The program header must have the form:
PROGRAM program_name;
READ, READLN, and EOLN (all without a file parameter) behave as in standard Pascal. WRITE and
WRITELN, also used without a file parameter, do not accept width specifiers for the output fields.
3. The only simple Pascal types are INTEGER, BOOLEAN, and CHAR. There are also other types related to
the control of concurrency; these will be discussed below.
4. A STRING type is supported. To declare a string, the length of the string must be specified. The
following declaration defines a string of length 20:
VAR
string_name : STRING[20];
BACI Pascal Compiler User’s Guide 3
The length specifier should be the number of characters that the string should have and should not
include space for the termination byte. The compiler takes care of reserving space for the termination
byte. The length specifier must be either a literal constant or a program constant.
The STRING keyword is used in the declaration of a procedure or function for declaring a parameter
of type STRING:
This declaration asserts that formal parm is of type STRING[n], for some positive value of n. Param-
eters of type STRING are passed by reference. No check for string overrun is performed.
5. Arrays of any valid type are supported. Array declaration follows the usual Pascal syntax:
8. In the declaration of variables of INTEGER and CHAR types, initializers are supported. The value of the
initializer must be a literal or program constant:
CONST
m = 5;
VAR
j : INTEGER := m;
k : INTEGER := 3;
c : CHAR := ’a’;
9. Procedures and functions are supported with both VAR and non-VAR parameters. Standard scope rules
apply. Recursion is supported.
10. The executable statements are IF-THEN-ELSE, FOR, REPEAT-UNTIL, and WHILE-DO. Statement brack-
eting with BEGIN-END is standard.
Both styles of include statement have the same semantics, because there is no “system” include
directory.
12. The EXTERNAL keyword for defining external variables is supported, but its usage varies from that of
Niklaus Wirth’s “standard” Pascal. In BACI Pascal, the EXTERNAL keyword precedes the definition of
the external object, whereas in Wirth’s Pascal, the keyword trails the definition of the object.
Any an external variable can be of any valid BACI Pascal type. Initializers cannot be used with
external variables. The EXTERNAL keyword can only occur at the global (“outer”) level, before the
PROGRAM keyword has appeared, if the source file contains a main program block.
BACI Pascal Compiler User’s Guide 4
Typical examples:
EXTERNAL VAR
i : INTEGER;
a : ARRAY [1..20] OF CHAR:
b : STRING[30];
// Initializers are not allowed ----> i : INTEGER := 30;
// (initialization, if present, must occur where i is defined)
EXTERNAL func(k : INTEGER) : INTEGER;
EXTERNAL MONITOR monSemaphore; // see Section 3. Only externally
PROCEDURE monP(); // visible details of the monitor
PROCEDURE monV(); // need be given here
END; // monSemaphore
The -c option must be used with bapas to compile source files that contain external references.
See the BACI System Separate Compilation Guide for more information about the use of external
variables.
3 Concurrency Constructs
3.1 COBEGIN—COEND
A process in BenAri Concurrent Pascal is a PROCEDURE. In the BACI system, the term “concurrent process”
is synonymous with the term “concurrent thread.” A list of processes to be run concurrently is enclosed in a
COBEGIN—COEND block. Such blocks cannot be nested and must appear in the main program.
COBEGIN
proc1(...); proc2(...); ... ; procN(...);
COEND;
The PCODE statements belonging to the listed procedures are interleaved by the interpreter in an ar-
bitrary, ‘random’ order, so that multiple executions of the same program containing a COBEGIN—COEND
block can appear to be non-deterministic. The main program is suspended until all of the processes in the
COBEGIN—COEND block terminate, at which time execution of the main program resumes at the statement
following the COEND statement.
3.2 Semaphores
The interpreter has a predeclared SEMAPHORE type. That is, a SEMAPHORE in BACI Concurrent Pascal is a
non-negative-valued INTEGER variable (see definition below) that can be accessed only in restricted ways.
The binary semaphore, one that only assumes the values 0 and 1, is supported by the BINARYSEM subtype of
the SEMAPHORE type. During compilation and execution, the compiler and interpreter enforce the restrictions
that a BINARYSEM variable can only have the values 0 or 1 and that a SEMAPHORE variable can only be non-
negative.
VAR
s : SEMAPHORE := 17;
b : BINARYSEM := 0;
BACI Pascal Compiler User’s Guide 5
is the only method available for initializing a semaphore of either type at runtime. In the call, the parameter
integer_expression can be any expression that evaluates to an integer value is valid for the semaphore
(non-negative for a SEMAPHORE type, or 0 or 1 for a BINARYSEM type). For example, the following two
INITIALSEM calls show an alternative way to initialize the two semaphores declared above:
INITIALSEM( s, 17);
INITIALSEM( b, 0);
or equivalently,
and
or equivalently,
The SEMAPHORE argument of each procedure is shown as a VAR parameter, because the procedure modi-
fies the value of the SEMAPHORE.
The semantics of the P and V procedure calls are as follows:
P(sem);
If sem > 0, then decrement sem by 1 and return, allowing P’s caller to continue.
If sem = 0, then put P’s caller to sleep. These actions are atomic, in that they are non-interruptible and
execute from start to finish.
V(sem);
If sem = 0 and one or more processes are sleeping on sem, then awake one of these processes. If
no processes are waiting on sem, then increment sem by one. In any event, V’s caller is allowed to
continue. These actions are atomic, in that they are non-interruptible and execute from start to finish.
Some implementations of V require that processes waiting on a semaphore be awakened in FIFO order
(queuing semaphores), but the BACI Interpreter conforms to Dijkstra’s original proposal by randomly
choosing which process to re-awaken when a signal arrives.
BACI Pascal Compiler User’s Guide 6
The program uses two semaphores. One semaphore, count, is of SEMAPHORE type, which indicates
to the BACI system that the semaphore will be allowed to have any non-negative value. The two con-
current procedures, increment and decrement, “signal” each other through the count semaphore. The
other semaphore, output, is of BINARYSEM type, which indicates to the BACI system that the semaphore
should always have the value zero or one; any other value causes a run-time exception. This semaphore is
used to keep the output from the two concurrently executing procedures, increment and decrement from
intermingling.
We produced the above compiler listing with the command
prompt% bapas semexample
Pcode and tables are stored in semexample.pco
Compilation listing is stored in semexample.lst
The semexample.pco file can then be executed with the BACI PCODE interpreter:
prompt% bainterp semexample
Source file: semexample.pm Thu May 9 09:47:54 2002
Executing PCODE ...
before V(count) value of count is 0
before P(count) value of count is 1
This execution of the PCODE file is one of the three possible outputs that the program can produce. The
other two possible program outputs are
BACI Pascal Compiler User’s Guide 7
An interested reader might find it instructive to supply explanations for ways in which these three pro-
gram outputs are generated and to show that these three outputs are the only outputs possible.
3.3 Monitors
The monitor concept, as proposed by Hoare, is supported with some restrictions. A MONITOR is a Pascal
block, like a block defined by a procedure or function, with some additional properties. All procedures and
functions in the monitor block are visible (that is, callable entry procedures) from the outside of the block,
but the monitor variables are not accessible outside of the block and can only be accessed by the procedures
and functions of the monitor. In BACI Concurrent Pascal, a monitor can be declared only at the outermost,
global level. Monitors can not be nested. The code between the BEGIN—END at the end of the monitor block
is run when the main program is started. Use this block to initialize the values of the monitor variables.
Only one procedure or function of the monitor block can execute at any given time. This feature makes
it possible to use monitors to implement mutual exclusion. Use of monitors to control concurrency is
advantageous because all of the code controlling concurrency is located in the monitor and not distributed
widely across callers, as is the case when semaphores are used.
Three constructs are used by the procedures and functions of a monitor to control concurrency: CONDITION
variables, WAITC (wait on a condition), and SIGNALC (signal a condition).
The priority scheme can be used to implement a FIFO discipline in re-awakening waiters. If each
MONITOR process increments a monitor variable associated with the current priority assigned to a condition,
then successive SIGNALC’s to the condition will awaken the sleeping processes in FIFO order.
The compiler provides a BOOLEAN-valued function EMPTY(cond) that returns TRUE if there are no pro-
cesses waiting in the queue of the condition cond and FALSE otherwise.
MONITOR monSemaphore;
VAR
semvalue : INTEGER;
notbusy : CONDITION;
PROCEDURE monP;
BEGIN
IF (semvalue > 0) THEN
WAITC(notbusy)
ELSE
semvalue := semvalue - 1;
END;
PROCEDURE monV;
BEGIN
IF (EMPTY(notbusy)) THEN
semvalue := semvalue + 1
ELSE
SIGNALC(notbusy);
END;
PROGRAM tas;
VAR
lock : INTEGER := 0;
BEGIN // tas
COBEGIN
proc(1); proc(2); proc(3);
COEND;
END.
VAR
x : STRING[20];
BEGIN
stringCopy(x,"Hello, world!");
stringCopy(x,"");
END.
will initialize the string x to a well-known value. The second stringCopy resets the string x to a zero-length
string. Either double-quotes (") or a single quote (’) can be used as delimiters of a raw string, but the two
types of delimiters cannot be mixed.
VAR
x : STRING[80];
y,z : STRING[15];
BEGIN
stringCopy(y,"alongstring");
stringCopy(z,"a long string");
sprintf(x,".%12d. .%-20s. .%q. .%08X.",202,y,z,0x3c03);
END.
The name of the source file is required. If missing, you will be prompted for it. The file suffix “.pm”
will be appended to the filename if you don’t supply it.
The name of the PCODE file is required. If missing, you will be prompted for it. The file suffix
“.pco” will be appended to the filename you give.
BACI Pascal Compiler User’s Guide 12
The following listing was produced by the BACI interpreter. The interpreter executes the program that
was compiled into the file “incremen.pco”.