``If, reader, you are slow now to believe What I shall tell, that is no cause for wonder, For I who saw it hardly can accept it.'' Dante Alighieri, Inferno, Canto XXV.
| byte | unsigned, 8 bits |
| int | signed, 32 bits |
| big | signed, 64 bits |
| real | IEEE long float, 64 bits |
nl := byte 10;
if (expr) stat if (expr) stat else stat while (expr) stat for (expr; expr; expr) stat do stat while (expr) ; return expr ; exit ;
implement Hello;
include "sys.m";
sys: Sys;
include "draw.m";
Hello: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
init(ctxt: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
sys->print("hello, world\n");
}
$ limbo -g hello.b
$ limbo -g hello.b $ emu Inferno main (pid=6559) interp Initialize Dis: /dis/sh.dis slocum.cs.bell-labs.com$ /usr/bwk/hello hello, world slocum.cs.bell-labs.com$
implement Hello2;
include "sys.m";
sys: Sys;
include "draw.m";
draw: Draw;
include "tk.m";
tk: Tk;
Hello2: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
init(ctxt: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
draw = load Draw Draw->PATH;
tk = load Tk Tk->PATH;
t := tk->toplevel(ctxt.screen, "");
tk->cmd(t, "button .b -text {hello, world}");
tk->cmd(t, "pack .b");
tk->cmd(t, "update");
sys->sleep(10000); # wait 10 seconds
}

...
t := tk->toplevel(ctxt.screen, "");
cmd := chan of string;
tk->namechan(t, cmd, "cmd"); # associate Limbo channel with Tk string
tk->cmd(t, "button .b -text {Delete me} -command {send cmd bye}");
tk->cmd(t, "pack .b");
tk->cmd(t, "update");
<- cmd; # wait for something to arrive on channel
}
# declarations omitted...
init(ctxt: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
argv = tl argv; # skip over program name
for (s := ""; argv != nil; argv = tl argv)
s += " " + hd argv;
if (s != "") # something was stored in s
sys->print("%s\n", s[1:]);
}
s := ""
# declarations omitted...
init(nil: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
buf := array[1] of byte;
stdin := sys->fildes(0);
OUT: con 0;
IN: con 1;
state := OUT;
nl := 0; nw := 0; nc := 0;
for (;;) {
n := sys->read(stdin, buf, 1);
if (n <= 0)
break;
c := int buf[0];
nc++;
if (c == '\n')
nl++;
if (c == ' ' || c == '\t' || c == '\n')
state = OUT;
else if (state == OUT) {
state = IN;
nw++;
}
}
sys->print("%d %d %d\n", nl, nw, nc);
}
nl := 0; nw := 0; nc := 0;
stdin := sys->fildes(0);
OUT: con 0;
IN: con 1;
state := OUT;
buf := array[1] of byte;
buf : array of byte; # no size at declaration buf = array[1] of byte; # size needed at creation
c := int buf[0];
# declarations omitted...
include "bufio.m";
bufmod: Bufio;
Iobuf: import bufmod;
iob: ref Iobuf;
init(nil: ref Draw->Context, nil: list of string)
{
sys = load Sys Sys->PATH;
bufmod = load Bufio Bufio->PATH;
if (bufmod == nil) {
sys->print("bufmod load: %r\n");
exit;
}
stdin := sys->fildes(0);
iob = bufmod->fopen(stdin, bufmod->OREAD);
if (iob == nil) {
sys->print("iob open: %r\n");
exit;
}
OUT: con 0;
IN: con 1;
state := OUT;
nl := 0; nw := 0; nc := 0;
for (;;) {
c := iob.getc();
if (c == bufmod->EOF)
break;
nc++;
if (c == '\n')
nl++;
if (c == ' ' || c == '\t' || c == '\n')
state = OUT;
else if (state == OUT) {
state = IN;
nw++;
}
}
sys->print("%d %d %d\n", nl, nw, nc);
}
include "bufio.m"; bufmod: Bufio;
Bufio: module # edited to fit your screen
{
PATH: con "/dis/bufio.dis";
EOF: con -1;
Iobuf: adt {
fd: ref Sys->FD; # the file
buffer: array of byte; # the buffer
# other variables omitted
getc: fn(b: self ref Iobuf) : int;
gets: fn(b: self ref Iobuf, sep: int) : string;
close: fn(b: self ref Iobuf);
};
open: fn(name: string, mode: int) : ref Iobuf;
fopen: fn(fd: ref Sys->FD, mode: int) : ref Iobuf;
};
Modulename->name
modulehandle->functionname modulehandle->variablename modulehandle->adtname.membername
iob: ref bufmod->Iobuf; bufmod->open(...) bufmod->iob.getc() bufmod->iob.fd
Iobuf: import bufmod;
adtvar := adtname(list of values for all members, in order); adtvar := ref adtname(list of values for all members, in order);
Hashtab: module
{
PATH: con "/usr/bwk/hashtab.dis"; # temporary name
Table: adt {
tab: array of list of (string, string);
alloc: fn(n: int) : ref Table;
hash: fn(ht: self ref Table, name: string) : int;
add: fn(ht: self ref Table, name: string, val: string);
lookup: fn(ht: self ref Table, name: string) : (int, string);
};
};
implement Hashtab;
include "hashtab.m";
Table.alloc(n: int) : ref Table
{
return ref Table(array[n] of list of (string,string));
}
Table.hash(ht: self ref Table, s: string) : int
{
h := 0;
for (i := 0; i < len s; i++)
h = (h << 1) ^ int s[i];
h %= len ht.tab;
if (h < 0)
h += len ht.tab;
return h;
}
Table.add(ht: self ref Table, name: string, val: string)
{
h := ht.hash(name);
for (p := ht.tab[h]; p != nil; p = tl p) {
(tname, nil) := hd p;
if (tname == name) {
# illegal: hd p = (tname, val);
return;
}
}
ht.tab[h] = (name, val) :: ht.tab[h];
}
Table.lookup(ht: self ref Table, name: string) : (int, string)
{
h := ht.hash(name);
for (p := ht.tab[h]; p != nil; p = tl p) {
(tname, tval) := hd p;
if (tname == name)
return (1, tval);
}
return (0, "");
}
(tname, tval) := hd p;
ht.tab[h] = (name, val) :: ht.tab[h];
(tname, nil) := hd p;
# illegal: hd p = (tname, val);
nvtab = Table.alloc(101); # make a Table
nvtab.add("Rob", "Pike");
nvtab.add("Howard", "Trickey");
(p, phil) := nvtab.lookup("Phil");
(q, sean) := nvtab.lookup("Sean");
Awk: module
{
PATH: con "/usr/bwk/awk.dis";
init: fn(argv: list of string);
getline: fn() : array of string;
NR: fn() : int;
NF: fn() : int;
FILENAME: fn() : string;
};
implement Awk;
include "sys.m";
sys: Sys;
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
iobuf: ref Iobuf;
include "awk.m";
_NR: int;
_NF: int;
_FILENAME: string;
argv: list of string;
init(av: list of string)
{
argv = tl av;
if (len argv == 0) # no args => stdin
argv = "-" :: nil;
sys = load Sys Sys->PATH;
bufio = load Bufio Bufio->PATH;
}
getline() : array of string
{
t := array[100] of string;
fl : list of string;
top:
while (argv != nil) {
if (_FILENAME == nil) { # advance to next file
_FILENAME = hd argv;
if (_FILENAME == "-")
iobuf = bufio->fopen(sys->fildes(0), bufio->OREAD);
else
iobuf = bufio->open(_FILENAME, bufio->OREAD);
if (iobuf == nil) {
sys->print("getline %s: %r\n", _FILENAME);
argv = nil;
return nil;
}
}
s := iobuf.gets('\n');
if (s == nil) {
iobuf.close();
_FILENAME = nil;
argv = tl argv;
continue top;
}
t[0] = s[0:len s - 1];
_NR++;
(_NF, fl) = sys->tokenize(t[0], " \t\n\r");
for (i := 1; fl != nil; fl = tl fl)
t[i++] = hd fl;
return t[0:i];
}
return nil;
}
NR() : int { return _NR; }
NF() : int { return _NF; }
FILENAME() : string { return _FILENAME; }
(_NF, fl) = sys->tokenize(t[0], " \t\n\r");
implement Fmt;
include "sys.m";
sys: Sys;
include "draw.m";
Fmt: module
{
init: fn(nil: ref Draw->Context, argv: list of string);
};
include "awk.m";
awk: Awk;
getline, NF: import awk;
out: array of string;
nout: int;
length: int;
linelen := 65;
init(nil: ref Draw->Context, argv: list of string)
{
t: array of string;
out = array[100] of string;
sys = load Sys Sys->PATH;
awk = load Awk Awk->PATH;
if (awk == nil) {
sys->print("load awk: %r\n");
return;
}
awk->init(argv);
nout = 0;
length = 0;
while ((t = getline()) != nil) {
nf := NF();
if (nf == 0) {
printline();
sys->print("\n");
} else for (i := 1; i <= nf; i++) {
if (length + len t[i] > linelen)
printline();
out[nout++] = t[i];
length += len t[i] + 1;
}
}
printline();
}
printline()
{
if (nout == 0)
return;
for (i := 0; i < nout-1; i++)
sys->print("%s ", out[i]);
sys->print("%s\n", out[i]);
nout = 0;
length = 0;
}
# declarations omitted...
WORD, BREAK, EOF : con iota;
wds: chan of (int, string);
init(nil: ref Draw->Context, nil: list of string)
{
sys = load Sys Sys->PATH;
bufmod = load Bufio Bufio->PATH;
stdin := sys->fildes(0);
iob = bufmod->fopen(stdin, bufmod->OREAD);
wds = chan of (int, string);
spawn getword(wds);
putword(wds);
}
getword(wds: chan of (int, string))
{
while ((s := iob.gets('\n')) != nil) {
(n, fl) := sys->tokenize(s, " \t\n");
if (n == 0)
wds <-= (BREAK, "");
else for ( ; fl != nil; fl = tl fl)
wds <-= (WORD, hd fl);
}
wds <-= (EOF, "");
}
putword(wds: chan of (int, string))
{
wd: int;
s: string;
for (length := 0;;) {
(wd, s) =<- wds;
case wd {
BREAK =>
sys->print("\n\n");
length = 0;
WORD =>
if (length + len s > 65) {
sys->print("\n");
length = 0;
}
sys->print("%s ", s);
length += len s + 1;
EOF =>
sys->print("\n");
exit;
}
}
}
'a' to 'z' or 'A' to 'Z' =>
tk->cmd("button .b -text {Push me} -command {send cmd .bpush}");

implement Etch;
include "sys.m";
sys: Sys;
include "draw.m";
draw: Draw;
include "tk.m";
tk: Tk;
Etch: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
init(ctxt: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
draw = load Draw Draw->PATH;
tk = load Tk Tk->PATH;
x, y, lastx, lasty: int;
t := tk->toplevel(ctxt.screen, "");
cmd := chan of string;
tk->namechan(t, cmd, "cmd");
tk->cmd(t, "canvas .c -height 400 -width 600 -background white");
tk->cmd(t, "frame .f");
tk->cmd(t, "button .f.c -text {Clear} -command {send cmd clear}");
tk->cmd(t, "button .f.d -text {Done} -command {send cmd quit}");
tk->cmd(t, "pack .f.c .f.d -side left -fill x -expand 1");
tk->cmd(t, "pack .c .f -side top -fill x");
tk->cmd(t, "bind .c <ButtonPress-1> {send cmd b1down %x %y}");
tk->cmd(t, "bind .c <Button-1-Motion> {send cmd b1motion %x %y}");
tk->cmd(t, "update");
for (;;) {
s := <-cmd;
(n, cmdstr) := sys->tokenize(s, " \t\n");
case hd cmdstr {
"quit" =>
exit;
"clear" =>
tk->cmd(t, ".c delete all; update");
"b1down" =>
lastx = int hd tl cmdstr;
lasty = int hd tl tl cmdstr;
cstr := sys->sprint(".c create line %d %d %d %d -width 2",
lastx, lasty, lastx, lasty);
tk->cmd(t, cstr);
"b1motion" =>
x = int hd tl cmdstr;
y = int hd tl tl cmdstr;
cstr := sys->sprint(".c create line %d %d %d %d -width 2",
lastx, lasty, x, y);
tk->cmd(t, cstr);
lastx = x; lasty = y;
}
tk->cmd(t, "update");
}
}
s := <-cmd

init(ctxt: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
draw = load Draw Draw->PATH;
tk = load Tk Tk->PATH;
wmlib = load Wmlib Wmlib->PATH;
wmlib->init();
tkargs := "";
argv = tl argv; # remove program name
if (argv != nil) { # and extract any -geom arg
tkargs = hd argv;
argv = tl argv;
}
(t, menubut) := wmlib->titlebar(ctxt.screen, tkargs, "Othello", Wmlib->Appl);
cmd := chan of string;
tk->namechan(t, cmd, "cmd");
tk->cmd(t, "canvas .c -height 400 -width 400 -background green");
tk->cmd(t, "frame .f");
tk->cmd(t, "label .f.l -text {Othello?} -background white");
tk->cmd(t, "button .f.c -text {Reset} -command {send cmd Reset}");
tk->cmd(t, "button .f.d -text {Quit} -command {send cmd Quit}");
tk->cmd(t, "pack .f.l .f.c .f.d -side left -fill x -expand 1");
tk->cmd(t, "pack .Wm_t .c .f -side top -fill x");
tk->cmd(t, "bind .c <ButtonRelease-1> {send cmd B1up %x %y}");
for (i := 1; i < 9; i++)
for (j := 1; j < 9; j++) {
coord := sys->sprint("%d %d %d %d",
SQ*i, SQ*j, SQ*(i+1), SQ*(j+1));
tk->cmd(t, ".c create rectangle " + coord +
" -outline black -width 2");
}
tk->cmd(t, "update");
lasterror(t, "init");
board = array[10] of {* => array[10] of int};
score = array[10] of {* => array[10] of int};
reinit();
for (;;) {
alt {
s := <- cmd =>
(n, l) := sys->tokenize(s, " \t");
case hd l {
"Quit" =>
exit;
"Reset" =>
reinit();
"B1up" =>
x := int hd tl l;
y := int hd tl tl l;
mouseUp(int x, int y);
}
menu := <-menubut =>
wmlib->titlectl(t, menu);
}
}
}
lasterror(t: ref Tk->Toplevel, where: string)
{
s := tk->cmd(t, "variable lasterror");
if (s != nil)
sys->print("%s: tk error %s\n", where, s);
}