Commit 66a603c9 authored by Ken Thompson's avatar Ken Thompson

arrays

R=r
OCL=14603
CL=14603
parent 30fd44cf
......@@ -157,12 +157,14 @@ dowidth(Type *t)
case TSTRING: // implemented as pointer
w = wptr;
break;
case TARRAY:
case TDARRAY:
fatal("width of a dynamic array");
case TARRAY:
if(t->type == T)
break;
dowidth(t->type);
w = t->bound * t->type->width;
w = t->bound * t->type->width
;// + offsetof(Array, b[0]);
break;
case TSTRUCT:
......
......@@ -136,6 +136,20 @@ cgen(Node *n, Node *res)
}
regalloc(&n1, nl->type, res);
cgen(nl, &n1);
if(isptrto(n->type, TARRAY) && isptrto(nl->type, TDARRAY)) {
// convert dynamic array to static array
n2 = n1;
n2.op = OINDREG;
n2.xoffset = offsetof(Array,array);
n2.type = types[tptr];
gins(AMOVQ, &n2, &n1);
}
if(isptrto(n->type, TDARRAY) && isptrto(nl->type, TARRAY)) {
// conver static array to dynamic array
// it is assumed that the dope is just before the array
nodconst(&n2, types[tptr], offsetof(Array,b));
gins(ASUBQ, &n2, &n1);
}
gmove(&n1, res);
regfree(&n1);
break;
......@@ -173,9 +187,33 @@ cgen(Node *n, Node *res)
regfree(&n1);
break;
}
if(isptrto(nl->type, TDARRAY)) {
regalloc(&n1, types[tptr], res);
cgen(nl, &n1);
n1.op = OINDREG;
n1.type = types[TUINT32];
n1.xoffset = offsetof(Array,nel);
gmove(&n1, res);
regfree(&n1);
break;
}
fatal("cgen: OLEN: unknown type %lT", nl->type);
break;
case OCAP:
if(isptrto(nl->type, TDARRAY)) {
regalloc(&n1, types[tptr], res);
cgen(nl, &n1);
n1.op = OINDREG;
n1.type = types[TUINT32];
n1.xoffset = offsetof(Array,cap);
gmove(&n1, res);
regfree(&n1);
break;
}
fatal("cgen: OCAP: unknown type %lT", nl->type);
break;
case OADDR:
agen(nl, res);
break;
......@@ -253,6 +291,7 @@ agen(Node *n, Node *res)
{
Node *nl, *nr;
Node n1, n2, n3, tmp;
Prog *p1;
uint32 w;
Type *t;
......@@ -347,15 +386,60 @@ agen(Node *n, Node *res)
// &a is in res
// i is in &n1
// w is width
nodconst(&n3, types[TINT64], w); // w/tint64
if(isptrto(nl->type, TDARRAY)) {
regalloc(&n2, types[tptr], res);
gmove(res, &n2);
if(!debug['B']) {
// check bounds
n3 = n2;
n3.op = OINDREG;
n3.type = types[tptr];
n3.xoffset = offsetof(Array, nel);
gins(optoas(OCMP, types[TUINT32]), &n1, &n3);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
nodconst(&n3, types[TUINT8], 5); // 5 is range trap
gins(AINT, &n3, N);
patch(p1, pc);
}
// fetch array base from dope
n3 = n2;
n3.op = OINDREG;
n3.type = types[tptr];
n3.xoffset = offsetof(Array, array);
gins(AMOVQ, &n3, &n2);
gmove(&n2, res);
regfree(&n2);
} else
if(!debug['B']) {
// check bounds
nodconst(&n3, types[TUINT32], nl->type->bound);
if(isptrto(nl->type, TARRAY))
nodconst(&n3, types[TUINT32], nl->type->type->bound);
gins(optoas(OCMP, types[TUINT32]), &n1, &n3);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
nodconst(&n3, types[TUINT8], 5); // 5 is range trap
gins(AINT, &n3, N);
patch(p1, pc);
}
t = types[TUINT64];
if(issigned[n1.type->etype])
regalloc(&n2, types[TINT64], &n1); // i/int64
else
regalloc(&n2, types[TUINT64], &n1); // i/uint64
t = types[TINT64];
regalloc(&n2, t, &n1); // i
gmove(&n1, &n2);
gins(optoas(OMUL, types[TINT64]), &n3, &n2);
gins(optoas(OADD, types[tptr]), &n2, res);
regfree(&n1);
nodconst(&n3, t, w); // w
gins(optoas(OMUL, t), &n3, &n2);
gins(optoas(OADD, types[tptr]), &n2, res);
regfree(&n2);
break;
......
......@@ -147,12 +147,17 @@ dumpexporttype(Sym *s)
break;
case TARRAY:
case TDARRAY:
reexport(t->type);
/* type 2 */
Bprint(bout, "\ttype ");
if(s->export != 0)
Bprint(bout, "!");
if(et == TDARRAY) {
Bprint(bout, "%lS [] %lS\n", s, t->type->sym);
break;
}
Bprint(bout, "%lS [%lud] %lS\n", s, t->bound, t->type->sym);
break;
......@@ -517,8 +522,13 @@ doimport2(Node *ss, Val *b, Node *st)
Type *t;
Sym *s;
t = typ(TARRAY);
t->bound = mpgetfix(b->u.xval);
if(b == nil) {
t = typ(TDARRAY);
t->dbound = N;
} else {
t = typ(TARRAY);
t->bound = mpgetfix(b->u.xval);
}
s = pkglookup(st->sym->name, st->psym->name);
t->type = s->otype;
......
......@@ -3,11 +3,6 @@
// license that can be found in the LICENSE file.
/*
todo:
1. dyn arrays
2. multi
tothinkabout:
2. argument in import
*/
#include <u.h>
......@@ -55,6 +50,21 @@ struct String
char s[3]; // variable
};
/*
* note this is the runtime representation
* of the compilers arrays. it is probably
* insafe to use it this way, but it puts
* all the changes in one place.
*/
typedef struct Array Array;
struct Array
{ // must not move anything
uchar array[8]; // pointer to data
uint32 nel; // number of elements
uint32 cap; // allocated number of elements
uchar b; // actual array - may not be contig
};
enum
{
Mpscale = 29, /* safely smaller than bits in a long */
......@@ -131,6 +141,7 @@ struct Type
// TARRAY
int32 bound;
Node* dbound;
};
#define T ((Type*)0)
......@@ -251,7 +262,7 @@ enum
ORETURN, OFOR, OIF, OSWITCH, OI2S, OS2I, OI2I,
OAS, OASOP, OCASE, OXCASE, OSCASE, OFALL, OXFALL,
OGOTO, OPROC, ONEW, OEMPTY, OSELECT,
OLEN, OPANIC, OPRINT, OTYPEOF,
OLEN, OCAP, OPANIC, OPRINT, OTYPEOF,
OOROR,
OANDAND,
......@@ -669,6 +680,7 @@ Type* fixmap(Type*);
Node* mapop(Node*, int);
Type* fixchan(Type*);
Node* chanop(Node*, int);
Node* arrayop(Node*, int);
Node* isandss(Type*, Node*);
Node* convas(Node*);
void arrayconv(Type*, Node*);
......
......@@ -18,7 +18,7 @@
%token <sym> LPACKAGE LIMPORT LEXPORT
%token <sym> LMAP LCHAN LINTERFACE LFUNC LSTRUCT
%token <sym> LCOLAS LFALL LRETURN
%token <sym> LNEW LLEN LTYPEOF LPANIC LPRINT
%token <sym> LNEW LLEN LCAP LTYPEOF LPANIC LPRINT
%token <sym> LVAR LTYPE LCONST LCONVERT LSELECT
%token <sym> LFOR LIF LELSE LSWITCH LCASE LDEFAULT
%token <sym> LBREAK LCONTINUE LGO LGOTO LRANGE
......@@ -733,6 +733,10 @@ pexpr:
{
$$ = nod(OLEN, $3, N);
}
| LCAP '(' expr ')'
{
$$ = nod(OCAP, $3, N);
}
| LTYPEOF '(' type ')'
{
$$ = nod(OTYPEOF, N, N);
......@@ -852,6 +856,7 @@ key:
| LFALSE
| LIOTA
| LLEN
| LCAP
| LPANIC
| LPRINT
| LNEW
......@@ -1519,6 +1524,11 @@ hidden_import:
// type array
doimport2($2, &$4, $6);
}
| LTYPE hidden_importsym '[' ']' hidden_importsym
{
// type array
doimport2($2, nil, $5);
}
| LTYPE hidden_importsym '(' ohidden_importsym_list ')'
{
// type function
......
......@@ -998,6 +998,7 @@ static struct
"map", LMAP, Txxx,
"new", LNEW, Txxx,
"len", LLEN, Txxx,
"cap", LCAP, Txxx,
"nil", LNIL, Txxx,
"package", LPACKAGE, Txxx,
"panic", LPANIC, Txxx,
......
......@@ -374,27 +374,39 @@ Type*
aindex(Node *b, Type *t)
{
Type *r;
r = typ(TARRAY);
r->type = t;
if(t->etype == TDARRAY)
yyerror("dynamic array type cannot be a dynamic array");
int bound;
walktype(b, Erv);
switch(whatis(b)) {
default:
yyerror("array bound must be a constant integer expression");
default: // variable bound
walktype(b, Erv);
if(b->type != T && isint[b->type->etype])
goto dyn;
yyerror("array bound must be an integer expression");
bound = 0;
break;
case Wnil: // default zero lb
r->bound = 0;
break;
case Wnil: // open bound
goto dyn;
case Wlitint: // fixed lb
r->bound = mpgetfix(b->val.u.xval);
case Wlitint: // fixed bound
bound = mpgetfix(b->val.u.xval);
break;
}
// fixed array
r = typ(TARRAY);
r->type = t;
r->dbound = b;
r->bound = bound;
return r;
dyn:
// dynamic array
r = typ(TDARRAY);
r->type = t;
r->dbound = b;
r->bound = 0;
return r;
}
......@@ -641,6 +653,7 @@ opnames[] =
[OLABEL] = "LABEL",
[OLE] = "LE",
[OLEN] = "LEN",
[OCAP] = "CAP",
[OLIST] = "LIST",
[OLITERAL] = "LITERAL",
[OLSH] = "LSH",
......@@ -1001,6 +1014,8 @@ Tconv(Fmt *fp)
case TDARRAY:
snprint(buf1, sizeof(buf1), "[]%T", t->type);
if(t->dbound != N)
snprint(buf1, sizeof(buf1), "[<expr>]%T", t->type);
strncat(buf, buf1, sizeof(buf));
break;
......@@ -1229,7 +1244,6 @@ eqtype(Type *t1, Type *t2, int d)
{
if(d >= 10)
return 1;
if(t1 == t2)
return 1;
if(t1 == T || t2 == T)
......@@ -1279,6 +1293,11 @@ eqtype(Type *t1, Type *t2, int d)
t2 = t2->down;
}
return 1;
case TARRAY:
if(t1->bound == t2->bound)
break;
return 0;
}
return eqtype(t1->type, t2->type, d+1);
}
......@@ -1304,6 +1323,8 @@ loop:
case TPTR32:
case TPTR64:
case TCHAN:
case TARRAY:
case TDARRAY:
stp = &st->type;
goto loop;
......@@ -1373,6 +1394,8 @@ deep(Type *t)
case TPTR32:
case TPTR64:
case TCHAN:
case TARRAY:
case TDARRAY:
nt = shallow(t);
nt->type = deep(t->type);
break;
......
......@@ -56,6 +56,11 @@ func selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
func selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
func selectgo(sel *byte);
func newarray(nel uint32, cap uint32, width uint32) (ary *[]any);
func arraysliced(old *[]any, lb uint32, hb uint32, width uint32) (ary *[]any);
func arrayslices(old *any, nel uint32, lb uint32, hb uint32, width uint32) (ary *[]any);
func arrays2d(old *any, nel uint32) (ary *[]any);
func gosched();
func goexit();
......@@ -124,6 +129,12 @@ export
selectrecv
selectgo
// dynamic arrays
newarray
arraysliced
arrayslices
arrays2d
// go routines
gosched
goexit
......
This diff is collapsed.
......@@ -429,17 +429,20 @@ loop:
}
}
if(t->etype == TARRAY) {
arrayconv(t, l);
// convert dynamic to static generated by ONEW
if(isptrto(t, TARRAY) && isptrto(l->type, TDARRAY))
goto ret;
}
// if(t->etype == TARRAY) {
// arrayconv(t, l);
// goto ret;
// }
r = isandss(n->type, l);
if(r != N) {
*n = *r;
goto ret;
}
badtype(n->op, l->type, t);
goto ret;
......@@ -566,6 +569,28 @@ loop:
n->type = types[TINT32];
goto ret;
case OCAP:
if(top != Erv)
goto nottop;
walktype(n->left, Erv);
evconst(n);
t = n->left->type;
if(t != T && isptr[t->etype])
t = t->type;
if(t == T)
goto ret;
switch(t->etype) {
default:
goto badt;
case TDARRAY:
break;
case TARRAY:
nodconst(n, types[TINT32], t->bound);
break;
}
n->type = types[TINT32];
goto ret;
case OINDEX:
case OINDEXPTR:
if(top == Etop)
......@@ -627,8 +652,8 @@ loop:
*n = *mapop(n, top);
break;
case TARRAY:
case TDARRAY:
case TARRAY:
// right side must be an int
if(n->right->type == T) {
convlit(n->right, types[TINT32]);
......@@ -672,10 +697,17 @@ loop:
walktype(n->right, Erv);
if(n->left == N || n->right == N)
goto ret;
if(isptrto(n->left->type, TSTRING)) {
t = n->left->type;
if(isptr[t->etype])
t = t->type;
if(t->etype == TSTRING) {
*n = *stringop(n, top);
goto ret;
}
if(t->etype == TDARRAY || t->etype == TARRAY) {
*n = *arrayop(n, top);
goto ret;
}
badtype(OSLICE, n->left->type, T);
goto ret;
......@@ -1403,6 +1435,9 @@ ascompat(Type *t1, Type *t2)
if(isptrto(t1, TSTRUCT))
return 1;
if(isptrto(t1, TDARRAY))
if(isptrto(t2, TARRAY))
return 1;
return 0;
}
......@@ -1498,13 +1533,19 @@ newcompat(Node *n)
fatal("newcompat: type should be pointer %lT", t);
t = t->type;
if(t->etype == TMAP) {
switch(t->etype) {
case TMAP:
r = mapop(n, Erv);
return r;
}
if(t->etype == TCHAN) {
case TCHAN:
r = chanop(n, Erv);
return r;
case TDARRAY:
case TARRAY:
r = arrayop(n, Erv);
return r;
}
if(n->left != N)
......@@ -2082,6 +2123,168 @@ shape:
return N;
}
Type*
fixarray(Type *tm)
{
Type *t;
t = tm->type;
if(t == T) {
fatal("fixarray: t nil");
return T;
}
if(t->etype != TDARRAY && t->etype != TARRAY) {
fatal("fixarray: %lT not array", tm);
return T;
}
if(t->type == T) {
fatal("fixarray: array element type is nil");
return T;
}
dowidth(t->type);
return t;
}
Node*
arrayop(Node *n, int top)
{
Node *r, *a;
Type *t;
Node *on;
Iter save;
r = n;
switch(n->op) {
default:
fatal("darrayop: unknown op %O", n->op);
case ONEW:
// newarray(nel uint32, max uint32, width uint32) (ary *[]any)
t = fixarray(n->type);
a = nodintconst(t->type->width); // width
a = nod(OCONV, a, N);
a->type = types[TUINT32];
r = a;
a = listfirst(&save, &n->left); // max
if(a == N)
a = nodintconst(0);
a = nod(OCONV, a, N);
a->type = types[TUINT32];
r = list(a, r);
a = t->dbound; // nel
if(a == N)
a = nodintconst(t->bound);
a = nod(OCONV, a, N);
a->type = types[TUINT32];
r = list(a, r);
on = syslook("newarray", 1);
argtype(on, t->type); // any-1
r = nod(OCALL, on, r);
walktype(r, top);
if(t->etype == TARRAY) {
// single case when we can convert a dynamic
// array pointer to a static array pointer
// saves making a sys function to alloc a static
r = nod(OCONV, r, N);
r->type = ptrto(t);
}
break;
case OAS:
// arrays2d(old *any, nel uint32) (ary *[]any)
t = fixarray(n->right->type);
a = nodintconst(t->bound); // nel
a = nod(OCONV, a, N);
a->type = types[TUINT32];
r = a;
a = n->right; // old
r = list(a, r);
on = syslook("arrays2d", 1);
argtype(on, n->right->type->type); // any-1
argtype(on, t->type); // any-2
r = nod(OCALL, on, r);
walktype(r, top);
n->right = r;
return n;
case OSLICE:
if(isptrto(n->left->type, TARRAY))
goto slicestatic;
// arrayslices(old *[]any, lb uint32, hb uint32, width uint32) (ary *[]any)
t = fixarray(n->left->type);
a = nodintconst(t->type->width); // width
a = nod(OCONV, a, N);
a->type = types[TUINT32];
r = a;
a = nod(OCONV, n->right->right, N); // hb
a->type = types[TUINT32];
r = list(a, r);
a = nod(OCONV, n->right->left, N); // lb
a->type = types[TINT32];
r = list(a, r);
a = n->left; // old
r = list(a, r);
on = syslook("arraysliced", 1);
argtype(on, t->type); // any-1
argtype(on, t->type); // any-2
r = nod(OCALL, on, r);
walktype(r, top);
break;
slicestatic:
// arrayslices(old *any, nel uint32, lb uint32, hb uint32, width uint32) (ary *[]any)
t = fixarray(n->left->type);
a = nodintconst(t->type->width); // width
a = nod(OCONV, a, N);
a->type = types[TUINT32];
r = a;
a = nod(OCONV, n->right->right, N); // hb
a->type = types[TUINT32];
r = list(a, r);
a = nod(OCONV, n->right->left, N); // lb
a->type = types[TINT32];
r = list(a, r);
a = nodintconst(t->bound); // nel
a = nod(OCONV, a, N);
a->type = types[TINT32];
r = list(a, r);
a = n->left; // old
r = list(a, r);
on = syslook("arrayslices", 1);
argtype(on, t); // any-1
argtype(on, t->type); // any-2
r = nod(OCALL, on, r);
walktype(r, top);
break;
}
return r;
}
void
diagnamed(Type *t)
{
......@@ -2178,37 +2381,48 @@ convas(Node *n)
return n;
}
if(isptrto(lt, TDARRAY) && isptrto(rt, TARRAY)) {
if(!eqtype(lt->type->type, rt->type->type, 0))
goto bad;
*n = *arrayop(n, Etop);
return n;
}
if(ascompat(lt, rt))
return n;
bad:
badtype(n->op, lt, rt);
return n;
}
void
arrayconv(Type *t, Node *n)
{
int c;
Iter save;
Node *l;
l = listfirst(&save, &n);
c = 0;
loop:
if(l == N) {
if(t->bound == 0)
t->bound = c;
if(t->bound == 0 || t->bound < c)
yyerror("error with array convert bounds");
return;
}
c++;
walktype(l, Erv);
convlit(l, t->type);
if(!ascompat(l->type, t->type))
badtype(OARRAY, l->type, t->type);
l = listnext(&save);
goto loop;
}
//void
//arrayconv(Type *t, Node *n)
//{
// int c;
// Iter save;
// Node *l;
//
// l = listfirst(&save, &n);
// c = 0;
//
//loop:
// if(l == N) {
// if(t->bound == 0)
// t->bound = c;
// if(t->bound == 0 || t->bound < c)
// yyerror("error with array convert bounds");
// return;
// }
//
// c++;
// walktype(l, Erv);
// convlit(l, t->type);
// if(!ascompat(l->type, t->type))
// badtype(OARRAY, l->type, t->type);
// l = listnext(&save);
// goto loop;
//}
Node*
old2new(Node *n, Type *t)
......
......@@ -20,6 +20,7 @@ LIBOFILES=\
runtime.$O\
map.$O\
chan.$O\
array.$O\
print.$O\
rune.$O\
proc.$O\
......
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "runtime.h"
static int32 debug = 0;
// newarray(nel uint32, cap uint32, width uint32) (ary *[]any);
void
sys·newarray(uint32 nel, uint32 cap, uint32 width, Array* ret)
{
Array *d;
uint64 size;
if(cap < nel)
cap = nel;
size = cap*width;
d = mal(sizeof(*d) - sizeof(d->b) + size);
d->nel = nel;
d->cap = cap;
d->array = d->b;
ret = d;
FLUSH(&d);
if(debug) {
prints("newarray: nel=");
sys·printint(nel);
prints("; cap=");
sys·printint(cap);
prints("; width=");
sys·printint(width);
prints("; ret=");
sys·printpointer(ret);
prints("\n");
}
}
// arraysliced(old *[]any, lb uint32, hb uint32, width uint32) (ary *[]any);
void
sys·arraysliced(Array* old, uint32 lb, uint32 hb, uint32 width, Array* ret)
{
Array *d;
if(hb > old->cap || lb > hb) {
if(debug) {
prints("sys·arrayslices: old=");
sys·printpointer(old);
prints("; lb=");
sys·printint(lb);
prints("; hb=");
sys·printint(hb);
prints("; width=");
sys·printint(width);
prints("\n");
prints("oldarray: nel=");
sys·printint(old->nel);
prints("; cap=");
sys·printint(old->cap);
prints("\n");
}
throw("sys·arraysliced: new size exceeds old size");
}
// new array is inside old array
d = mal(sizeof(*d) - sizeof(d->b));
d->nel = hb-lb;
d->cap = old->cap - lb;
d->array = old->array + lb*width;
ret = d;
FLUSH(&d);
if(debug) {
prints("sys·arrayslices: old=");
sys·printpointer(old);
prints("; lb=");
sys·printint(lb);
prints("; hb=");
sys·printint(hb);
prints("; width=");
sys·printint(width);
prints("; ret=");
sys·printpointer(ret);
prints("\n");
}
}
// arrayslices(old *any, nel uint32, lb uint32, hb uint32, width uint32) (ary *[]any);
void
sys·arrayslices(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, Array* ret)
{
Array *d;
if(hb > nel || lb > hb) {
if(debug) {
prints("sys·arrayslices: old=");
sys·printpointer(old);
prints("; nel=");
sys·printint(nel);
prints("; lb=");
sys·printint(lb);
prints("; hb=");
sys·printint(hb);
prints("; width=");
sys·printint(width);
prints("\n");
}
throw("sys·arrayslices: new size exceeds cap");
}
// new array is inside old array
d = mal(sizeof(*d) - sizeof(d->b));
d->nel = hb-lb;
d->cap = nel-lb;
d->array = old + lb*width;
ret = d;
FLUSH(&d);
if(debug) {
prints("sys·arrayslices: old=");
sys·printpointer(old);
prints("; nel=");
sys·printint(nel);
prints("; lb=");
sys·printint(lb);
prints("; hb=");
sys·printint(hb);
prints("; width=");
sys·printint(width);
prints("; ret=");
sys·printpointer(ret);
prints("\n");
}
}
// arrays2d(old *any, nel uint32) (ary *[]any)
void
sys·arrays2d(byte* old, uint32 nel, Array* ret)
{
Array *d;
// new dope to old array
d = mal(sizeof(*d) - sizeof(d->b));
d->nel = nel;
d->cap = nel;
d->array = old;
ret = d;
FLUSH(&d);
if(debug) {
prints("sys·arrays2d: old=");
sys·printpointer(old);
prints("; nel=");
sys·printint(nel);
prints("; ret=");
sys·printpointer(ret);
prints("\n");
}
}
......@@ -37,6 +37,7 @@ typedef struct String *string;
typedef struct Sigs Sigs;
typedef struct Sigi Sigi;
typedef struct Map Map;
typedef struct Array Array;
typedef struct Gobuf Gobuf;
typedef struct G G;
typedef struct M M;
......@@ -99,6 +100,14 @@ struct Sigi
uint32 hash;
uint32 offset;
};
struct Array
{ // must not move anything
byte* array; // actual data
uint32 nel; // number of elements
uint32 cap; // allocate3d number of elements
byte b[8]; // actual array - may not be contig
};
struct Map
{
Sigi* si;
......
......@@ -325,7 +325,7 @@ func Split(U PS) *dch2{
func Add(U, V PS) PS{
Z := mkPS();
go func(U, V, Z PS){
var uv *[2] *rat;
var uv *[] *rat;
for {
<-Z.req;
uv = get2(U,V);
......@@ -419,9 +419,9 @@ func Shift(c *rat, U PS) PS{
// Convert array of coefficients, constant term first
// to a (finite) power series
/* BUG: NEED LEN OF ARRAY
func Poly(a [] *rat) PS{
Z:=mkPS();
/* BUG: NEED LEN OF ARRAY
begin func(a [] *rat, Z PS){
j:=0;
done:=0;
......@@ -431,9 +431,9 @@ func Poly(a [] *rat) PS{
for(; i<j; i=i+1) put(a[i],Z);
put(finis,Z);
}();
*/
return Z;
}
*/
// Multiply. The algorithm is
// let U = u + x*UU
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment