All I know about rsc.io/c2go
Moriyoshi Koizumi
Open Collector, Inc.
Hey
I can be found amongst CONTRIBUTORS :)
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
こんにちは、世界
void print(char *fmt, ...);
void main()
{
print("Hello, %s.n", "world");
}
⬇️ bin/c2go -dst $GOPATH hello.c
package main
func main() {
fmt.Printf("Hello, %s.n", "world")
}
(generated under $GOPATH/src/main)
Quicksort1
Quicksort1
Involves pointer arithmetics, compound types, and function pointers.
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;
}
...
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);
}
...
Quicksort1 (code)
...
void main() {
int i;
Data values[] = { { 1 }, { 9 }, { 5 }, { 2 }, { 4 }, { 3 }, { 8 }, { 6 }, { 7 } };
_qsort(values, 9, cmp);
for (i = 0; i < 9; i++)
print("%dn", values[i].v);
}
Quicksort1
Compile:
$ cc -o qsort1 qsort1.c $GO_1_4_ROOT/pkg/obj/darwin_amd64/lib9.a
Run:
$ ./qsort1
1
2
3
4
5
6
7
8
9
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
}
...
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)
...
Quicksort2
Quicksort2
int print(const char *fmt, ...);
typedef struct Data {
int v;
} Data;
typedef struct DataSlice {
Data *p;
int len;
int cap;
} DataSlice;
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;
}
...
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]);
...
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);
}
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}
}
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
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!
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) {
...
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 %
Quicksort2
The configuration file gives more control over the generated code.
Its directives are not totally demystified yet.
Quicksort3
Quicksort3
This is CHEATING
void qsort(void *d, int l, int s, int(*cmp)(void *, void *));
int print(char *fmt, ...);
typedef struct Data {
int v;
} Data;
int cmp(void *a, void *b)
{
Data *_a, *_b;
_a = a;
_b = b;
if (_a->v < _b->v)
return -1;
else if (_a->v > _b->v)
return 1;
else
return 0;
}
...
Quicksort3
...
void main() {
int i;
Data values[] = { { 1 }, { 9 }, { 5 }, { 2 }, { 4 }, { 3 }, { 8 }, { 6 }, { 7 } };
qsort(values, 9, sizeof(values[0]), cmp);
for (i = 0; i < 9; i++)
print("%dn", values[i].v);
}
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]
}
...
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)
}
}
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.
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;
}
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!
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)
All I know about rsc.io/c2go

All I know about rsc.io/c2go

  • 1.
    All I knowabout rsc.io/c2go Moriyoshi Koizumi Open Collector, Inc.
  • 2.
    Hey I can befound amongst CONTRIBUTORS :)
  • 3.
    rsc.io/c2go C to Gotranslation 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
  • 4.
    こんにちは、世界 void print(char *fmt,...); void main() { print("Hello, %s.n", "world"); } ⬇️ bin/c2go -dst $GOPATH hello.c package main func main() { fmt.Printf("Hello, %s.n", "world") } (generated under $GOPATH/src/main)
  • 5.
  • 6.
    Quicksort1 Involves pointer arithmetics,compound types, and function pointers.
  • 7.
    Quicksort1 (code) int print(constchar *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); } ...
  • 9.
    Quicksort1 (code) ... void main(){ int i; Data values[] = { { 1 }, { 9 }, { 5 }, { 2 }, { 4 }, { 3 }, { 8 }, { 6 }, { 7 } }; _qsort(values, 9, cmp); for (i = 0; i < 9; i++) print("%dn", values[i].v); }
  • 10.
    Quicksort1 Compile: $ cc -oqsort1 qsort1.c $GO_1_4_ROOT/pkg/obj/darwin_amd64/lib9.a Run: $ ./qsort1 1 2 3 4 5 6 7 8 9
  • 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) ...
  • 13.
  • 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.lenDataSlice.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 ita second try: $ go run $GOPATH/src/main/qsort2.go 1 2 3 4 5 6 7 8 9 WOW %
  • 23.
    Quicksort2 The configuration filegives more control over the generated code. Its directives are not totally demystified yet.
  • 24.
  • 25.
    Quicksort3 This is CHEATING voidqsort(void *d, int l, int s, int(*cmp)(void *, void *)); int print(char *fmt, ...); typedef struct Data { int v; } Data; int cmp(void *a, void *b) { Data *_a, *_b; _a = a; _b = b; if (_a->v < _b->v) return -1; else if (_a->v > _b->v) return 1; else return 0; } ...
  • 26.
    Quicksort3 ... void main() { inti; Data values[] = { { 1 }, { 9 }, { 5 }, { 2 }, { 4 }, { 3 }, { 8 }, { 6 }, { 7 } }; qsort(values, 9, sizeof(values[0]), cmp); for (i = 0; i < 9; i++) print("%dn", values[i].v); }
  • 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 aMAGIC. 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 wantto 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)