.DE\
.bp\
.DS\
-.ft 5\
+.ft CW\
.ta 0.65i 1.3i 1.95i 2.6i 3.25i 3.9i 4.55i 5.2i 5.85i 6.5i/'
In addition to the normal assignment statement, Occam has two more
information-transfer statements, the input and the output:
.DS
-.ft 5
+.ft CW
chan1 ? x -- reads a value from chan1 into x
chan2 ! x -- writes the value of x onto chan2
.ft
.PP
\fIProducer-consumer example:\fP
.DS
-.ft 5
+.ft CW
.nf
CHAN buffer: -- declares the channel buffer
PAR
.PP
\fIExample: 20 window-sorters in series:\fP
.DS
-.ft 5
+.ft CW
.nf
CHAN s[20]: -- 20 channels
PAR i = [ 0 FOR 19 ] -- 19 processes
.NH 2
The LLgen Parser Generator
.PP
-LLgen accepts a Context Free syntax extended with the operators `\f5*\fP', `\f5?\fP' and `\f5+\fP'
+LLgen accepts a Context Free syntax extended with the operators `\f(CW*\fP', `\f(CW?\fP' and `\f(CW+\fP'
that have effects similar to those in regular expressions.
-The `\f5*\fP' is the closure set operator without an upperbound; `\f5+\fP' is the positive
-closure operator without an upperbound; `\f5?\fP' is the optional operator;
-`\f5[\fP' and `\f5]\fP' can be used for grouping.
+The `\f(CW*\fP' is the closure set operator without an upperbound; `\f(CW+\fP' is the positive
+closure operator without an upperbound; `\f(CW?\fP' is the optional operator;
+`\f(CW[\fP' and `\f(CW]\fP' can be used for grouping.
For example, a comma-separated list of expressions can be described as:
.DS
-.ft 5
+.ft CW
expression_list:
expression [ ',' expression ]*
;
.ft
.DE
.LP
-Alternatives must be separated by `\f5|\fP'.
+Alternatives must be separated by `\f(CW|\fP'.
C code (``actions'') can be inserted at all points between the colon and the
semicolon.
Variables global to the complete rule can be declared just in front of the
-colon enclosed in the brackets `\f5{\fP' and `\f5}\fP'. All other declarations are local to
+colon enclosed in the brackets `\f(CW{\fP' and `\f(CW}\fP'. All other declarations are local to
their actions.
Nonterminals can have parameters to pass information.
A more mature version of the above example would be:
.DS
-.ft 5
+.ft CW
expression_list(expr *e;) { expr e1, e2; } :
expression(&e1)
[ ',' expression(&e2)
An alternation confict arises if two sides of an alternation can start with the
same symbol. E.g.
.DS
-.ft 5
+.ft CW
plus: '+' | '+' ;
.ft
.DE
-The parser doesn't know which `\f5+\fP' to choose (neither do we).
+The parser doesn't know which `\f(CW+\fP' to choose (neither do we).
Such a conflict can be resolved by putting an \fBif-condition\fP in front of
the first conflicting production. It consists of a \fB``%if''\fP followed by a
C-expression between parentheses.
If a conflict occurs (and only if it does) the C-expression is evaluated and
parsing continues along this path if non-zero. Example:
.DS
-.ft 5
+.ft CW
plus:
%if (some_plusses_are_more_equal_than_others())
'+'
.ft
.DE
A repetition conflict arises when the parser cannot decide whether
-``\f5productionrule\fP'' in e.g. ``\f5[ productionrule ]*\fP'' must be chosen
+``\f(CWproductionrule\fP'' in e.g. ``\f(CW[ productionrule ]*\fP'' must be chosen
once more, or that it should continue.
This kind of conflicts can be resolved by putting a \fBwhile-condition\fP right
after the opening parentheses. It consists of a \fB``%while''\fP
list:
.DS
.nf
-.ft 5
+.ft CW
comma_expression:
sub_expression
[ %while (not_part_of_comma_separated_list())
and one process:
.DS
.nf
-.ft 5
+.ft CW
seq i = [ 1 for str[byte 0] ]
out ! str[byte i]
.ft
and one without a replicator and several processes:
.DS
.nf
-.ft 5
+.ft CW
seq
in ? c
out ! c
The LLgen skeleton grammar to handle these two is:
.DS
.nf
-.ft 5
+.ft CW
SEQ { line=yylineno; oind=ind; }
[ %if (line==yylineno)
replicator
.DS C
\fIFigure 1. Interprocess and outside world communication channels\fP
.DE
-The basic channel handling is done by \f5chan_in\fP and \f5chan_out\fP. All
-other routines are based on them. The routine \f5chan_any\fP only checks if
+The basic channel handling is done by \f(CWchan_in\fP and \f(CWchan_out\fP. All
+other routines are based on them. The routine \f(CWchan_any\fP only checks if
there's a value available on a given channel. (It does not read this value!)
-\f5C_init\fP initializes an array of interprocess communication channels.
+\f(CWC_init\fP initializes an array of interprocess communication channels.
.LP
The following table shows Occam statements paired with the routines used to
execute them.
T}
.sp 0.5
.TE
-The code of \f5c_init\fP, \f5chan_in\fP, \f5chan_out\fP and \f5chan_any\fP
+The code of \f(CWc_init\fP, \f(CWchan_in\fP, \f(CWchan_out\fP and \f(CWchan_any\fP
can be found in Appendix A.
.NH 3
Synchronization on interprocess communication channels
\fBNOW\fP evaluates to the current time returned by the time(2) system call.
The code is simply:
.DS
-.ft 5
+.ft CW
.nf
long now()
{
\fBerror\fP, that corresponds with the standard error file.
.IP -
\fBfile\fP, an array of channels that can be subscripted with an index
-obtained by the builtin named process ``\f5open\fP''. Note that
+obtained by the builtin named process ``\f(CWopen\fP''. Note that
\fBinput\fP=\fBfile\fP[0], \fBoutput\fP=\fBfile\fP[1] and
\fBerror\fP=\fBfile\fP[2].
.LP
Builtin named processes to open and close files are defined as
.DS
.nf
-.ft 5
+.ft CW
proc open(var index, value name[], mode[]) = ..... :
proc close(value index) = ..... :
.fi
.DE
To open a file `junk', write nonsense onto it, and close it, goes as follows:
.DS
-.ft 5
+.ft CW
.nf
var i:
seq
(i.e. no echoing of typed characters and no line buffering).
.LP
To exit an Occam program, e.g. after an error, a builtin named process
-\f5exit\fP is available that takes an exit code as its argument.
+\f(CWexit\fP is available that takes an exit code as its argument.
.NH 2
Replicators and slices
.PP
Both the base and the count of replicators like in
.DS
-.ft 5
+.ft CW
par i = [ base for count ]
.ft
.DE
may be arbitrary expressions. The count in array slices like in
.DS
-.ft 5
+.ft CW
c ? A[ base for count ]
.ft
.DE
According to the occam syntax the \fBANY\fP keyword may be the only argument of
an input or output process. Thus,
.DS
-.ft 5
+.ft CW
c ? ANY; x
.ft
.DE
.NH
Appendix A: Implementation of the channel routines
.DS L
-.ft 5
+.ft CW
.ta 0.65i 1.3i 1.95i 2.6i 3.25i 3.9i 4.55i 5.2i 5.85i 6.5i
.so channel.h.t
.ft
.DE
.bp
.DS L
-.ft 5
+.ft CW
.ta 0.65i 1.3i 1.95i 2.6i 3.25i 3.9i 4.55i 5.2i 5.85i 6.5i
.so channel.c.t
.ft
.PP
Translation of the parallel construct:
.DS
-.ft 5
+.ft CW
par
P0
par i = [ 1 for n ]
So the major part of the code of a target optimizer is
shared among all target optimizers.
.DS
-.ft 5
+.ft CW
|-------------------------|
.nf
Examples of mnemonic descriptions:
-.ft 5
+.ft CW
add
sub.l
.nf
Examples:
-.ft 5
+.ft CW
(sp)+
r5
a \fIrestriction\fR to which its value is subjected.
.nf
Example of variable declarations:
-.ft 5
+.ft CW
CONST { VAL[0] == '$' };
REG { VAL[0] == 'r' && VAL[1] >= '0' && VAL[1] <= '3' &&
An operand description given via a variable name matches an
actual operand if the actual operand obeys the associated restriction.
.nf
-.ft 5
+.ft CW
CONST matches $1, $-5, $foo etc.
REG matches r0, r1, r2 and r3
.nf
Example:
-.ft 5
+.ft CW
FERMAT_NUMBER { VAL[0] == '$' && is_fermat_number(&VAL[1]) };
string_constant1 variable_name string_constant2
Example:
-.ft 5
+.ft CW
(REG)+ matches (r0)+, (r1)+, (r2)+ and (r3)+
.LP
.nf
The pattern:
-.ft 5
+.ft CW
dec REG : move.b CONST,(REG)
.ft R
matches:
-.ft 5
+.ft CW
dec r0 : move.b $4,(r0)
.ft R
but not:
-.ft 5
+.ft CW
dec r0 : move.b $4,(r1)
the same restriction.
.nf
Example:
-.ft 5
+.ft CW
REG1,REG2 { VAL[0] == 'r' && ..... };
The expression may refer to the variables and to ANY.
.nf
Example:
-.ft 5
+.ft CW
move REG1,REG2 { REG1[1] == REG2[1] + 1 }
.ft R
matches
-.ft 5
+.ft CW
move r1,r0
move r2,r1
Suppose the table contains the following declarations:
.nf
-.ft 5
+.ft CW
X, LOG { TRUE };
LAB { VAL[0] == 'L' }; /* e.g. L0017 */
A { no_side_effects(VAL) };
included in the table.
.PP
.nf
-.ft 5
+.ft CW
\fIentry:\fP addl3 X,A,A -> addl2 X,A;
.ft R
instruction.
An optimization like:
.nf
-.ft 5
+.ft CW
addl3 r0,(r2)+,(r2)+ -> addl2 r0,(r2)+
be side-effect free.
.PP
.nf
-.ft 5
+.ft CW
\fIentry:\fP addw2 $-NUM,X -> subw2 $NUM,X;
.ft R
very efficiently on the Vax.
.PP
.nf
-.ft 5
+.ft CW
\fIentry:\fP bitw $NUM,A : jneq LAB
{ is_poweroftwo(NUM,LOG) } -> jbs $LOG,A,LAB;
A "jbs n,x,l" branches to l if bit n of x is set.
So, for example, the following transformation is possible:
.nf
-.ft 5
+.ft CW
bitw $32,r0 : jneq L0017 -> jbs $5,r0,L0017
Suppose we have the following declarations:
.nf
-.ft 5
+.ft CW
X { TRUE };
A { no_side_effects(VAL) };
L1, L2 { VAL[0] == 'I' };
differ for the PDP-11 and the Vax.
.PP
.nf
-.ft 5
+.ft CW
\fIentry:\fP mov REG,A : ANY A,X -> mov REG,A : ANY REG,X ;
.ft R
and A is used as source (first) operand, it is cheaper to use REG instead.
.PP
.nf
-.ft 5
+.ft CW
\fIentry:\fP jeq L1 : jbr L2 : labdef L1 -> jne L2 : labdef L1;
.ft R
looks like, this must be expressed in the table (see Appendix A).
.PP
.nf
-.ft 5
+.ft CW
\fIentry:\fP add $01,X { carry_dead(REST) } -> inc X;
.ft R
as it is possible that instructions that were rejected earlier now do match.
For example, consider the following patterns:
.DS
-.ft 5
+.ft CW
cmp $0, X -> tst X ;
mov REG,X : tst X -> move REG.X ; /* redundant test */
.ft R
.DE
If the input is:
.DS
-.ft 5
+.ft CW
mov r0,foo : cmp $0,foo
.ft R
.DE
then the first instruction is initially rejected.
However, after the transformation
.DS
-.ft 5
+.ft CW
cmp $0,foo -> tst foo
.ft R
.DE
the following optimization is possible:
.DS
-.ft 5
+.ft CW
mov r0,foo : tst foo -> mov r0,foo
.ft R
.DE
beginning with a letter.
.PP
.DS
-.ft 5
+.ft CW
table -> {parameter_line} '%%;' {variable_declaration} '%%;'
{entry} '%%;' user_routines.
.ft R
user-supplied subroutines.
.PP
.DS
-.ft 5
+.ft CW
parameter_line -> identifier value ';' .
.ft R
.DE
Optimization does, however, proceed with the rest of the input.
.PP
.DS
-.ft 5
+.ft CW
variable_declaration -> identifier {',' identifier} restriction ';' .
restriction -> '{' anything '}' .
The expression may contain calls to procedures that are defined in the
user-routines section.
.DS
-.ft 5
+.ft CW
entry -> pattern '->' replacement ';' .
pattern -> instruction_descr
rest of the input. (REST is a null-string if this mnemonic can
not be determined).
.DS
-.ft 5
+.ft CW
user_routines -> anything .
.ft R
.DE