3. rsc.io/c2go
C to Go translation tool behind the Go's self-hosting effort.
Written by rsc.
Apparently not intended to be a generic translation tool.
$ go get rsc.io/c2go
7. Quicksort1 (code)
int print(const char *fmt, ...);
typedef struct Data {
int v;
} Data;
void swap(Data *a, Data *b)
{
Data v = *a;
*a = *b;
*b = v;
}
int cmp(Data *a, Data *b)
{
if (a->v < b->v)
return -1;
else if (a->v > b->v)
return 1;
else
return 0;
}
...
8. Quicksort1 (code)
...
void _qsort(Data *d, int l, int (*cmp)(Data *a, Data *b))
{
int pivot, le, i, j;
Data pv;
if (l == 0)
return;
le = l - 1;
pivot = l / 2;
pv = d[pivot];
swap(&d[pivot], &d[le]);
i = 0;
for (j = 0; j < le; j++) {
if (cmp(&d[j], &pv) < 0) {
swap(&d[i], &d[j]);
i++;
}
}
swap(&d[i], &d[le]);
_qsort(d, i, cmp);
if (l > i)
_qsort(&d[i + 1], l - (i + 1), cmp);
}
...
11. Quicksort1
Translate:
$ c2go -dst $GOPATH qsort1.c
No worry about the message; this is a warning.
main/qsort1.go: cannot find copyright notice in C file qsort1.c
Generated code:
package main
type Data struct {
v int
}
func swap(a *Data, b *Data) {
var v Data = *a
*a = *b
*b = v
}
...
12. Quicksort1
...
func _qsort(d *Data, l int, cmp func(*Data, *Data) int) {
var pivot int
var le int
var i int
var j int
var pv Data
if l == 0 {
return
}
le = l - 1
pivot = l / 2
pv = d[pivot]
swap(&d[pivot], &d[le])
...
Looks like it went well so far, but Aw, Snap! #
src/main/qsort1.go:24: invalid operation: d[pivot] (type *Data does not support indexing)
src/main/qsort1.go:25: invalid operation: d[pivot] (type *Data does not support indexing)
src/main/qsort1.go:25: invalid operation: d[le] (type *Data does not support indexing)
...
14. Quicksort2
int print(const char *fmt, ...);
typedef struct Data {
int v;
} Data;
typedef struct DataSlice {
Data *p;
int len;
int cap;
} DataSlice;
15. Quicksort2
...
void swap(Data *a, Data *b)
{
Data v = *a;
*a = *b;
*b = v;
}
int cmp(Data *a, Data *b)
{
if (a->v < b->v)
return -1;
else if (a->v > b->v)
return 1;
else
return 0;
}
...
16. Quicksort2
...
void _qsort(DataSlice *ds, int (*cmp)(Data *a, Data *b))
{
int pivot, le, i, j;
Data pv;
if (ds->len == 0)
return;
le = ds->len - 1;
pivot = ds->len / 2;
pv = ds->p[pivot];
swap(&ds->p[pivot], &ds->p[le]);
i = 0;
for (j = 0; j < le; j++) {
if (cmp(&ds->p[j], &pv) < 0) {
swap(&ds->p[i], &ds->p[j]);
i++;
}
}
swap(&ds->p[i], &ds->p[le]);
...
17. Quicksort2
...
{
DataSlice ns = { ds->p, i, ds->cap };
_qsort(&ns, cmp);
}
if (ds->len > i) {
DataSlice ns = { &ds->p[i + 1], ds->len - (i + 1), ds->cap - (i + 1) };
_qsort(&ns, cmp);
}
}
void main() {
int i;
Data values[] = { { 1 }, { 9 }, { 5 }, { 2 }, { 4 }, { 3 }, { 8 }, { 6 }, { 7 } };
DataSlice s = { values, 9, 9 };
_qsort(&s, cmp);
for (i = 0; i < 9; i++)
print("%dn", values[i].v);
}
18. Quicksort2
my.cfg:
slice DataSlice.p DataSlice.len DataSlice.cap
diff {
- var ns = DataSlice{ds.p, i, cap(ds.p)}
+ var ns = DataSlice{ds.p[0:i]}
}
diff {
- var ns = DataSlice{&ds.p[i+1], len(ds.p) - (i + 1), cap(ds.p) - (i + 1)}
+ var ns = DataSlice{ds.p[i+1:]}
}
diff {
- var s = DataSlice{values, 9, 9}
+ var s = DataSlice{values}
}
19. Quicksort2
Translate:
c2go -c my.cfg -dst $GOPATH qsort2.c
Forget all the unfamiliar messages; these are warnings:
qsort2.c:39: too many fields in braced initializer of DataSlice
qsort2.c:43: too many fields in braced initializer of DataSlice
qsort2.c:61: too many fields in braced initializer of DataSlice
main/qsort2.go: cannot find copyright notice in C file qsort2.c
20. Quicksort2
Generated Code:
...
func _qsort(ds *DataSlice, cmp func(*Data, *Data) int) {
var pivot int
var le int
var i int
var j int
var pv Data
if len(ds.p) == 0 {
return
}
le = len(ds.p) - 1
pivot = len(ds.p) / 2
pv = ds.p[pivot]
swap(&ds.p[pivot], &ds.p[le])
i = 0
for j = 0; j < le; j++ {
if cmp(&ds.p[j], &pv) < 0 {
...
Looks pretty promising!
21. Quicksort2
$ go run $GOPATH/src/main/qsort2.go
# command-line-arguments
src/main/qsort2.go:66: undefined: fmt in fmt.Printf
Seems we had to add import "fmt" manually $
package main
import "fmt" // here
type Data struct {
v int
}
func swap(a *Data, b *Data) {
...
22. Quicksort2
Let's give it a second try:
$ go run $GOPATH/src/main/qsort2.go
1
2
3
4
5
6
7
8
9
WOW %
27. Quicksort3
Translate:
$ c2go -dst $GOPATH qsort3.c
Generated code:
package main
type Data struct {
v int
}
type cmp []Data
func (x cmp) Len() int {
return len(x)
}
func (x cmp) Swap(i, j int) {
x[i], x[j] = x[j], x[i]
}
...
28. Quicksort3
...
func (x cmp) Less(i, j int) bool {
var _a *Data
var _b *Data
_a = &x[i]
_b = &x[j]
if _a.v < _b.v {
return true
} else if _a.v > _b.v {
return 1 < 0
} else {
return false
}
}
func main() {
var i int
var values = []Data{Data{1}, Data{9}, Data{5}, Data{2}, Data{4}, Data{3}, Data{8}, Data{6}, Data{7}}
sort.Sort(cmp(values[:9]))
for i = 0; i < 9; i++ {
fmt.Printf("%dn", values[i].v)
}
}
29. Quicksort3
This is a MAGIC.
Some "standard" C functions are treated specially so that they get translated into the Go's
counterparts.
print() ➡️ fmt.Printf()
qsort() ➡️ sort.Sort()
memset() / memmove()
strcpy() / strcat / strlen() / strcmp()
malloc() / strdup() / free()
abort() '
DISCLAIMER: this is just informational; not a complete list.
30. Quicksort3
If you want to get the MAGIC happening right, You need to make sure...
The prototype:
void qsort(void *d, int l, int s, int(*cmp)(void *, void *));
The third argument cmp() function:
void cmp(void *a, void *b)
{
type_in_question *a_, *b_;
a_ = a;
b_ = b;
}
not
void cmp(void *a, void *b)
{
type_in_question *a_ = a, *b_ = b;
}
31. Quicksort3
Call to qsort():
qsort(list, nitems, sizeof(list[0]), cmp);
not
qsort(list, nitems, sizeof(type_in_question), cmp);
Want to go further?
See src/rsc.io/c2go/typecheck.go.
More magics can be added!
32. Thank you
2015/6/21 1:15:00(2015/6/21%201:15:00)
Tags: golang, c2go(#ZgotmplZ)
Moriyoshi Koizumi
Open Collector, Inc.
mozo@mozo.jp(mailto:mozo@mozo.jp)
http://mozo.jp/(http://mozo.jp/)
@moriyoshit(http://twitter.com/moriyoshit)