Alef User’s Guide
Bob Flandrena
Introduction
         
            
              

          
             
          
          
              
            
           
          

 Alef Language Reference Manual       
             
           
      
            
            
            
              

Overview
            
             
            
            
         alef     
          
             
              alef
          

 alef.h  
               
           
           
           
              


               
 Processes           
        Tasks     
            
           main 
            
       channels     


 



  

           
 
          proc
  process         
 
proc func(1, 2);
      func       
 proc 
  channel          
              
  chan 
chan(int) c;
   c       
         alloc     

alloc c; /* allocate channel named ’c’ */
   <−=          

c <−= 1+1; /* send a 2 on channel ‘c’ */
    <−        
            


int i;
i = <−c; /* assign value received on c to i */
func(<−c); /* pass value received on c to func */
           

#include <alef.h>
void
receive(chan(byte*) c)
{
byte *s;
s = <−c;
print("%s\n", s);
terminate(nil);
}
void
main(void)
{
chan(byte*) c;
alloc c;
proc receive(c);
c <−= "hello world";
print("done\n");
terminate(nil);
}
           
              
           
    receive        
              
            

           
            
           

Types
             byte
     char  unsigned char    
           ints  lints   
           float    

             
  union aggr adt  tuple Unions  aggrs   
unions  structs Adts  tuples        

 aggr       struct  typedef

 
aggr Point {
int x;
int y;
};

typedef struct {
int x;
int y;
} Point;
               
            
            
           
               
 Circle
aggr Circle {
int radius;
Point;
};
Circle c;
            
Line
aggr Line {
Point p1;
Point p2;
};
Line ln;
 Point 
            . 
               
 −>            
           
            
              
             
           Circle  c.x 
c.y             
ln.p1.x ln.p1.y ln.p2.x ln.p2.y
              
            
          
            
 
Point p;
Circle c;
p=c;
 Point   Circle  c   Point  p
             
              

             
 
int
eqpt(Point p1, Point p2)
{
return p1.x == p2.x && p1.y == p2.y;
}
void
main(void)
{
Point p;
Circle c;
if(eqpt(c, p)) ...
}
    eqpt      Point   
Circle           eqpt 
 Points
if(eqpt(&c, &p)) ...
       Circle      
 Point 
             
            
           
 Line  Circle
aggr Shape {
int type;
union {
Circle;
Line;
};
};
Shape s;
  union Line  Circle       
  s.dummy.circ.pt.x s.x      x   
Circle   s.p1.x    x    
Point  Line 
             
 
Shape s;
memset(&s.Circle, 0, sizeof(s.Circle));
 Circle  Shape 
Tuples
tuple           
              aggr 
              

     tuple      


tuple(int, byte*, int) t;
   t        tuple 
                
 
tuple(int, tuple(byte, byte*), int) t;

            
           
 sizeof             

              
            
            

(1+2, "abc", var)
      intbyte       
  var         

             
             
            
                 
             
             
               
 
tuple(int, int, byte*) t;
byte i;
t = (0, (int) i, "abc");
t = (tuple (int, int, byte*)) (0, i, "abc");
           t  
   i      byte   int 
            

               
        nil       
             
             
      nil      
             
            
 

float a;
byte *b;
tuple(int, int, byte*) t;
t = (100, 200, "xyz");
(nil, a, b) = t;
 a  b
             
            
 
Circle c;
Point p;
int rad;
(rad, p) = c;
 Circle          
              
            
               
 
Circle c;
c = (Circle)(3, (1.0,1.0));
c = (3, (Point)(1.0,1.0));
      Circle     
 float  
c = (3, (1,1));
              
       Circle      
             

      
           
 
int a, b;
(b,a) = (a,b);
 a  b
            
           
            
            
             
             
                

             
            
 

Point
midpoint(Point p1, Point p2)
{
return ((p1.x+p2.x)/2,(p1.y+p2.y)/2);
}
void
main(void)
{
Point p;
p = midpoint((1,1), (3,1));
}
    midpoint        

           
    strtoui       
             
              
              

tuple(int, uint, byte*)
strtoui(byte* str, int base)
{
int val;
while(*str != 0 && whitespace(*str))
str++;
if(str == nil || *str == 0)
return(0, 0, str);
while(*str && !whitespace(*str)) {
if(!validdigit(*str, base))
return (−1, val, str+1);
/* extract digit into val */
str++;
}
return(1, val, str);
}

int ret;
uint val;
byte *p, *newp;
while(*p) {
(ret, val, newp) = strtoui(p, 10);
if(ret == 0)
break;
if(ret < 0) {
*newp = 0;
print("bad number %s\n", p);
} else
print("%d\n", val);
p = newp;
}
              

 
tuple(int, byte*, byte*) func();
int a;
byte *b, *c;
(a, b, c) = func();
print("tuple = (%d %s %s)\n", a, b, c);
 func
Processes
            
             
     proc       
               
             
             

           
            
             
        
            
           
         
                 
           
             
           

  proc          
             

          
            
         exits 
       atexit  
        terminate     
           terminate 
exits          
  exits 
             
  exits    terminate     
      proc  task    terminate 

           
          
             
             
            
            
             


          
 
void
kbdproc(chan(int) kbdc)
{
byte c;
int n, fd, ctlfd;
fd = open("/dev/cons", OREAD);
ctlfd = open("/dev/consctl", OWRITE);
write(ctlfd, "rawon", 5); /* set raw mode */
for(;;) {
n = read(fd, &c, 1);
if(n <= 0 || c == 0x04) {
kbdc <−= −1;
return;
}
n = processinput(c);
if(n)
kbdc <−= n;
}
}
Kbdproc             
    processinput        
        
            
            
     
 
void
main(void)
{
int r;
chan(int) kbd;
alloc kbd;
proc kbdproc(kbd);
for(;;) {
r = <−kbd;
if(r < 0)
terminate(nil);
/* process the input value */
}
}
            
            
            
           
         
            

              
  Mevent 

aggr Mevent {
Point;
int buttons;
};
            
          
             alt
           switch 

alt {
case <−c0: /* receive & discard input on channel c0 */
break;
case r = <−c1: /* receive input on channel c1 into r*/
break;
case c2 <−= 1: /* send 1 on c2 when there is a receiver*/
break;
}
            
            
      case        
            
       alt      
   default   switch      


void
mouseproc(chan(Mevent) mc)
{
int fd, n;
byte buf[1024];
Mevent m;
fd = open("/dev/mouse", OREAD);
for(;;) {
n = read(fd, buf, sizeof(buf));
if(n <= 0)
continue;
m = decodemouse(buf, n);
mc <−= m;
}
}
           
decodemouse       Mevent      

            
alt 

void
main(void)
{
int r;
Mevent m;
chan(int) kbd;
chan(Mevent) mouse;
alloc kbd, mouse;
proc kbdproc(kbd), mouseproc(mouse);
for(;;) {
alt {
case r = <−kbd:
if(r < 0)
terminate(nil);
/* process keyboard input */
break;
case m = <−mouse:
/* process mouse event */
break;
}
}
}
           
            
           
             
           
           
 alt 
int kbdpid, mousepid;
void
kbdproc(chan(int) kbdc, chan(int) termc)
{
byte c;
int n, fd, ctlfd;
kbdpid = getpid();
fd = open("/dev/cons", OREAD);
ctlfd = open("/dev/consctl", OWRITE);
write(ctlfd, "rawon", 5); /* set raw mode */
for(;;) {
n = read(fd, &c, 1);
if(n <= 0 || c == EOF) {
termc <−= −1;
return;
}
n = processinput(c);
if(n)
kbdc <−= n;
}
}

void
mouseproc(chan(Mevent) mc, chan(int) termc)
{
int fd, n;
byte buf[1024];
Mevent m;
mousepid = getpid();
fd = open("/dev/mouse", OREAD);
for(;;) {
n = read(fd, buf, sizeof(buf));
if(n < 0) {
termc <−= 1;
return;
}
m = decodemouse(buf, n);
mc <−= m;
}
}
void
main(void)
{
int r;
Mevent m;
chan(int) kbd, term;
chan(Mevent) mouse;
alloc kbd, mouse, term;
proc kbdproc(kbd, term), mouseproc(mouse, term);
for(;;) {
alt {
case <−term: /* kill slave processes */
postnote(PNPROC, mousepid, "kill");
postnote(PNPROC, kbdpid, "kill");
exits(nil);
case r = <−kbd:
/* process keyboard input */
break;
case m = <−mouse:
/* process mouse event */
break;
}
}
}
             
             
           
case   alt            
           
    
            


Asynchronous Channels
            
             
             

          
        
            
             
           
            
              
           

          
 
chan(int)[100] kbd;
           
              
               
              
            
         
          
             

            
            
              
           
              

Tasks
          
 task              
             
              
            
            
               
            
             
      

             
         
            
         
          
         

           

              proc 
     task        
            
       terminate     
               
            
terminate          
              
      exits        
             

              
           
            
 
void
kbdtask(chan(int) kbdc)
{
int r;
for(;;) {
r = <−kbdc;
/* process keyboard input */
}
}
void
mousetask(chan(Mevent) mc)
{
Mevent m;
for(;;) {
m = <−mc;
/* process mouse input */
}
}
void
main(void)
{
chan(int)[100] kbd;
chan(int) term;
chan(Mevent) mouse;
alloc kbd, mouse, term;
proc kbdproc(kbd, term), mouseproc(mouse, term);
task kbdtask(kbd), mousetask(mouse);
<−term; /* main thread blocks here */
postnote(PNPROC, mousepid, "kill");
postnote(PNPROC, kbdpid, "kill");
exits(nil);
}
            

              
                 
             
             
               
             
               
             
             alt 
             
exits             
              
                
            

Resource Servers
            
           
             
           
              
             

          
            
              
           
           
           
             

            
            
               
            
             
             
              
            
             

           
             
               

  ?            
           can−receive 
              
  can−send           
            
            
              

            

if(?ch)
a = <−ch;
              
              
            
              
            
          
  alt            
 
chan(int)[1] dummy;
alloc dummy;
dummy <−= 1; /* fill the channel */
while(?ch)
alt {
case a = <−ch:
/* process message */
break 2; /* break from while loop */
case <−dummy:
dummy <−= 1; /* refill channel */
break;
}
 alt            
 ch            
           
                
    alt        break  
  while             
           

               
 
void
alarmproc(chan(tuple(int, chan(int))) alrmch)
{
uint t;
int a, dt;
chan(int)[1] dummy;
chan(int) reply;
alarmpid = getpid();
alloc dummy;
dummy <−= 1;
alist = nil;
t = msec();

for(;;) {
if(alist == nil) {
/* no alarms − get client request */
(a, reply) = <−alrmch;
addalarm(alist, a, reply);
t = msec();
} else while(?alrmch) {
alt {
case (a, reply) = <−alrmch:
addalarm(alist, a, reply);
break 2;
case <−dummy:
dummy <−= 1;
break;
}
}
sleep(1); /* sleep 1ms */
dt = msec()−t;
t += dt;
for(each alarm in alist) {
if(alarm.msec <= dt) {
/* send alarm to client */
alarm.ch <−= 1;
deletealarm(alarm);
} else
alarm.msec −= dt;
}
}
}
              
       
            
      msec       
              
               
           
             

             
             
               alt
 
              
             



void
mousetask(chan(Mevent) mc, chan(tuple(int, chan(int))) alarm)
{
Mevent m, lastm;
chan(int) dummy, ch;
alloc dummy;
ch = dummy;
for(;;) {
alt {
case m = <−mc:
if((m.buttons&0x07) == 0)
break;
if(ch == dummy) {
/* no alarm pending */
alloc ch;
alarm <−= (500, ch);
lastm = m;
} else {
task consumealarm(ch);
ch = dummy;
if(lastm.buttons == m.buttons
&& eqpt(lastm.Point, m.Point))
doubleclick(m);
else
singleclick(m);
}
break;
case <−ch: /* alarm expired */
unalloc ch;
ch = dummy;
singleclick(lastm);
break;
}
}
}
void
consumealarm(chan(int) ch)
{
<−ch;
unalloc ch;
}
       alt      
            
ch             
          ch     
         alt      
              
 ch           alt    
            
              
       ch         alt
              
             
     ch       
alt            

             
       ch        alt
                
              
             
            
      consumealarm     
           
             
               
            

              
               

void
main(void)
{
chan(int)[100] kbd;
chan(int) term;
chan(Mevent) mouse;
chan(tuple(int, chan(int))) alarm;
alloc kbd, mouse, term, alarm;
proc kbdproc(kbd, term), mouseproc(mouse, term),
alarmproc(alarm);
task kbdtask(kbd), mousetask(mouse, alarm);
<−term; /* main thread blocks here */
postnote(PNPROC, mousepid, "kill");
postnote(PNPROC, kbdpid, "kill");
postnote(PNPROC, alarmpid, "kill");
exits(nil);
}
          
     alt        
             
           
      
   

Miscellaneous Channel Topics
           
              
            
              
              

           
            
          sizeof 
           
 

chan(int)[100] ch[2];
alloc ch[0], ch[1];

               
              
            
             
                 

Abstract Data Types
              
             
             
            
       

            
 adt    aggr  union        
             
 
           
              
              
                

              
      Mouse  Keyboard    
           
               Mouse
 Keyboard           Mevent
Mouse  Keyboard 
adt Mevent {
Point;
int buttons;
int fill(*Mevent, byte*, int);
};
adt Mouse {
Mevent;
extern chan(Mevent) ch;
chan(int) term;
int fd;
int pid;
Mouse* init(byte*, chan(int));
void close(*Mouse);
intern void mproc(*Mouse);
};

adt Keyboard {
extern chan(int)[100] ch;
chan(int) term;
int kbdfd;
int ctlfd;
int pid;
Keyboard* init(byte*, chan(int));
void close(*Keyboard);
int ctl(*Keyboard, byte*);
intern void kproc(*Keyboard);
};
 Mouse            
              
     Mevent      
       Keyboard     
            
   intern            
extern             
             

             
           
            
               
             
              
 init 
            
              
               
             
           
          
             
              
               
          fill     
  Mouse        Mevent 

          typename.method 
typename              
     Mouse     Mouse.init 
 Mouse 
int
Mevent.fill(Mevent *m, byte *buf, int n)
{
if(n < 10)
return 0;
/* decode ’buf’ into ’m’ */
return 1;
}

Mouse*
Mouse.init(byte *device, chan(int) term)
{
Mouse *m;
alloc m;
m−>fd = open(device, OREAD);
if(m−>fd < 0) {
unalloc m;
return nil;
}
alloc m−>ch;
m−>term = term;
proc m−>mproc();
return m;
}
void
Mouse.close(Mouse *m)
{
if(m−>pid)
postnote(PNPROC, m−>pid, "kill");
}
void
Mouse.mproc(Mouse *m)
{
int n;
byte buf[1024];
m−>pid = getpid();
for(;;) {
n = read(m−>fd, buf, sizeof(buf));
if(n < 0) {
m−>term <−= −1;
continue;
}
if(m−>fill(buf, n))
m−>ch <−= m−>Mevent;
}
}
          
             

proc m−>mproc();
         Mouse    
              
fill    Mevent          
Mevent 
 Keyboard 

Keyboard*
Keyboard.init(byte *device, chan(int) term)
{
Keyboard *k;
byte buf[128];
alloc k;
k−>kbdfd = open(device, OREAD);
if(k−>kbdfd < 0) {
unalloc k;
return nil;
}
sprint(buf, "%sctl", device);
k−>ctlfd = open(buf, OWRITE);
if(k−>ctlfd < 0) {
unalloc k;
close(k−>kbdfd);
return nil;
}
alloc k−>ch;
k−>term = term;
k−>ctl("rawon");
proc k−>kproc();
return k;
}
void
Keyboard.kproc(Keyboard *k)
{
byte c;
int n;
k−>pid = getpid();
for(;;) {
n = read(k−>kbdfd, &c, 1);
if(n <= 0 || c == EOF) {
k−>term <−= −1;
continue;
}
n = processinput(c);
if(n)
k−>ch <−= n;
}
}
void
Keyboard.close(Keyboard *k)
{
if(k−>pid)
postnote(PNPROC, k−>pid, "kill");
}
int
Keyboard.ctl(Keyboard *k, byte *msg)
{
return write(k−>ctlfd, msg, strlen(msg));
}

            
               
             
              
     .  −>       

Keyboard k, *kp;
k.ctl("rawon");
kp−>ctl("rawon");
  ctl    Keyboard       
    ctl          
               &k
 kp
               
            
          
         .typename.method  
     Mouse      .Mouse.init(args)
            nil  
             
   nil     ((Mouse*)nil)−>
init(args)
              
               
            

  Mouse  Keyboard        

void
main(void)
{
Mouse *m;
Keyboard *k;
chan(tuple(int, chan(int))) alarm;
chan(int) term;
alloc term, alarm;
m = .Mouse.init("/dev/mouse", term);
if(m == nil)
exits("mouse");
k = .Keyboard.init("/dev/cons", term);
if(k == nil) {
m−>close();
exits("keyboard");
}
proc alarmproc(alarm);
task kbdtask(k−>ch), mousetask(m−>ch, alarm);

<−term; /* main thread blocks here */
k−>close();
m−>close();
postnote(PNPROC, alarmpid, "kill");
exits(nil);
}
             
 
Error Handling

 check            
             
           
              
check             
             
             
 
n = write(−1, buf, len);
check n == len, "write error";

test.l:7:main() write error, errstr(file not open)
          ALEFcheck

void (*ALEFcheck)(byte*, byte*);

               
  
check           
          
 Check            
 −c 
 rescue          raise 
            
             
    raise  goto      
          rescue   
          
            

      rescue  raise     
  raise          
    raise       
  raise 
           
             
            goto
             


      rescue  raise     
            

byte*
findfile(byte *dirname, byte *string)
{
int n, dirfd, fd;
byte *buf, buf2[512];
Dir d;
n = strlen(string);
buf = malloc(n);
rescue {
unalloc buf;
return nil;
}
dirfd = open(dirname, OREAD);
if(dirfd < 0)
raise;
rescue closedir{
close(dirfd);
raise;
}
while(dirread(dirfd, &d, sizeof(d)) == DIRLEN) {
sprint(buf2, "%s/%s", dirname, d.name);
fd = open(buf2, OREAD);
if(fd < 0)
continue;
rescue {
close(fd);
continue;
}
if(read(fd, buf, n) <= 0)
raise;
close(fd);
if(strncmp(buf, string, n) == 0) {
close(dirfd);
unalloc buf;
buf = malloc(strlen(d.name)+1);
strcpy(buf, d.name);
return buf;
}
}
werrstr("no match");
raise closedir;
return nil; /* needed to fool compiler */
}
   raise         
            raise 
   rescue   closedir     
              
               


Parallel Execution
 par             
       par       
              par
             
          
          
 par 
 par 
par {
statement 1;
statement 2;
...
statement n;
}
             
            
           
   par           
par          par      

   par         
     par      
              par
            

 par         
             
          
           
            
 
void
main(int, byte **argv)
{
byte *active, *passive;
int fd, n;
fd = open(argv[1], OREAD);
check fd >= 0, "open error";
active = malloc(BUFSIZE);
passive = malloc(BUFSIZE);

n = decode(fd, active, BUFSIZE); /* first block */
check n > 0, "read error";
while(active != nil) {
par {
display(active, BUFSIZE);
if(decode(fd, passive, BUFSIZE) <= 0)
passive = nil;
}
(active, passive) = (passive, active);
waitforinput();
}
}
   decode         
       display    
   waitforinput       
     display  decode      
 par 
Allocators
 alloc   malloc     
Alloc                
            Malloc  
                  
              
        check   

       alloc     
        Alloc    

typedef byte* Ptrs[5];
byte **p;
int *ip;
Ptrs *c;
alloc p, ip, c;
alloc *c[0], *c[1], *c[2], *c[3], *c[4];
             
    p ip c      c  Alloc
               
         c   c  
 alloc 
alloc c, *c[0], *c[1], *c[2], *c[3], *c[4];
 c 
Unalloc           
  alloc  malloc      unalloc 
            
 unalloc  free

Iterators
    ::        
           
             
             
            
            
             
              

           
              

alloc c, *c[0::5];
        
 c           
  c          
 
int i, a[10];
a[i=0::10] = i;
print("%d ", a[0::10]);
0 1 2 3 4 5 6 7 8 9 
typedef float Matrix[4][4];
void mul(Matrix r, Matrix a, Matrix b){
int i, j, k;
r[0::4][0::4] = 0;
r[i=0::4][j=0::4] += a[i][k=0::4]*b[k][j];
}
           
             
           
              
         k     

QLocks and Locks
 QLock        QLock.lock
       QLock.unlock
             
          
QLock.canlock               
 QLocks            
    QLock         

 QLock  malloc  alloc  
             
QLock              QLock
               QLock 


           
         
          
            
              
          
             
          
            
           
             
             
       
          Display  
  QLock           
              

 QLock         Lock   
   Locks       QLocks  
        Lock.lock   
               
              
Lock.unlock            
Lock.canlock                
             
             

Guarded Blocks
           
guarded block            
               
              


<unguarded code>
!{
<code in guarded block>
}
<unguarded code>
    



intern int fd = −1;
int
time()
{
int t;
byte b[20];
memset(b, 0, sizeof(b));
if(fd < 0)
fd = open("/dev/time", OREAD|OCEXEC);
if(fd >= 0) {
seek(fd, 0, 0);
read(fd, b, sizeof(b));
}
t = atoi(b);
return t;
}
              
                
 
              
            
   seek  read         

if(fd >= 0) !{
seek(fd, 0, 0);
read(fd, b, sizeof(b));
}
            if 
             
                
         

!{
if(fd < 0)
fd = open("/dev/time", OREAD|OCEXEC);
if(fd >= 0) {
seek(fd, 0, 0);
read(fd, b, sizeof(b));
}
}
    par       
               
              
     par       
            
terminate          

The ... Formal Parameter
   ...        
    ...       ... 
             

  ...               
       ...        
           
       ...     
              

 ...     

int
avg(int n, ...)
{
int i, tot;
tot = 0;
for(i = 0; i < n; i++)
tot += ((int*)...)[i];
return tot/n;
}
 ...              

  ...             
 doprint  
byte *argv0;
void
fatal(byte *fmt, ...)
{
byte buf[1024], *p;
p = doprint(buf, buf+sizeof(buf), fmt, ...);
*p = 0;
fprint(2, "%s: %s\n", argv0, buf);
exits(buf);
}
              

The Become Statement
 become             
    become   return   
           
             
            
            
            
           
            
become            
become 
    become          
               


___________________________

___________________________

___________________________

___________________________

___________________________

___________________________
              
         

void stateA(chan(int));
void stateB(chan(int));
void stateC(chan(int));
int readcpid;
void
readc(chan(int) c)
{
int fd, fd2;
byte ch;
readcpid = getpid();
fd = open("/dev/cons", OREAD);
fd2 = open("/dev/consctl", OWRITE);
check fd >= 0 && fd2 >= 0, "keyboard open";
write(fd2, "rawon", 5);
for(;;) {
check read(fd, &ch, 1) == 1, "read error";
c <−= ch;
}
}
void
stateA(chan(int) c)
{
print("A");
switch(<−c) {
default:
case ’1’: become stateA(c);
case ’2’: become stateB(c);
case ’3’: become stateC(c);
}
}
void
stateB(chan(int) c)
{
print("B");
switch(<−c) {
default:
case ’3’:
case ’1’: become stateB(c);
case ’2’: become stateA(c);
}
}

void
stateC(chan(int) c)
{
print("C");
switch(<−c) {
default: become stateC(c);
case ’1’: become stateA(c);
case ’2’: become stateB(c);
case ’3’: print("\n"); /* terminal state */
break;
}
if(readcpid)
postnote(PNPROC,readcpid, "kill");
exits(nil);
}
void
main(void)
{
chan(int) c;
alloc c;
proc readc(c);
stateA(c);
}
            
 become 
Alef Libraries
    libA.a      libc.a 
   libA.a       
             
alef.h           
         
           

     libbio.a       
            Biobuf 
            
<bio.h>             
 getd           
             
B             
             
            

Miscellaneous Features
   USED           
           
           
      ‘−w’       


void
main(int, byte**)
{
...
}

            
             
     ALEF_stack     
              
           ALEF_stack    
 task  proc 
  ALEF_rflags        
           fork  
 ALEF_rflags  RFPROC|RFMEM|RFNOWAIT 
               
            sproc 
     PR_SFDS|PR_SADDR      
           

            
           
               
             
              proc
         
          
 ALEF_rflags      proc 
 ALEF_rflags 