This source file includes following definitions.
- xgetchar
- xungetc
- xputchar
- xisspace
- bad_eof
- free_params
- getchar_update_lineno
- getchar_no_eof
- getchar_skipping_comments
- read_token
- read_token_no_eof
- read_package
- read_preprocessor_lines
- read_type
- type_size
- read_params
- read_func_header
- write_params
- write_6g_func_header
- write_6g_func_trailer
- define_gcc_return_type
- write_gcc_return_type
- write_gcc_func_header
- write_gcc_func_trailer
- write_func_header
- write_func_trailer
- copy_body
- process_file
- goc2c
#include "a.h"
static char *input;
static Buf *output;
#define EOF -1
enum
{
        use64bitint = 1,
};
static int
xgetchar(void)
{
        int c;
        
        c = *input;
        if(c == 0)
                return EOF;
        input++;
        return c;
}
static void
xungetc(void)
{
        input--;
}
static void
xputchar(char c)
{
        bwrite(output, &c, 1);
}
static int
xisspace(int c)
{
        return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}
static int gcc;
static const char *file;
static unsigned int lineno;
struct params {
        struct params *next;
        char *name;
        char *type;
};
enum {
        Bool,
        Float,
        Int,
        Uint,
        Uintptr,
        String,
        Slice,
        Eface,
        Complex128,
        Float32,
        Float64,
};
static struct {
        char *name;
        int size;
        int rnd; 
} type_table[] = {
        
        {"bool",        1},
        {"float",       4},
        {"intgo",               4},
        {"uintgo",      4},
        {"uintptr",     4},
        {"String",      8},
        {"Slice",       12},
        {"Eface",       8},
        {"Complex128", 16},
        
        {"float32",     4},
        {"float64",     8},
        {"byte",        1},
        {"int8",        1},
        {"uint8",       1},
        {"int16",       2},
        {"uint16",      2},
        {"int32",       4},
        {"rune",        4},
        {"uint32",      4},
        {"int64",       8},
        {"uint64",      8},
        {nil, 0},
};
int structround = 4;
static void
bad_eof(void)
{
        fatal("%s:%d: unexpected EOF\n", file, lineno);
}
static void
free_params(struct params *p)
{
        while (p != nil) {
                struct params *next;
                next = p->next;
                xfree(p->name);
                xfree(p->type);
                xfree(p);
                p = next;
        }
}
static int
getchar_update_lineno(void)
{
        int c;
        c = xgetchar();
        if (c == '\n')
                ++lineno;
        return c;
}
static int
getchar_no_eof(void)
{
        int c;
        c = getchar_update_lineno();
        if (c == EOF)
                bad_eof();
        return c;
}
static int
getchar_skipping_comments(void)
{
        int c;
        while (1) {
                c = getchar_update_lineno();
                if (c != '/')
                        return c;
                c = xgetchar();
                if (c == '/') {
                        do {
                                c = getchar_update_lineno();
                        } while (c != EOF && c != '\n');
                        return c;
                } else if (c == '*') {
                        while (1) {
                                c = getchar_update_lineno();
                                if (c == EOF)
                                        return EOF;
                                if (c == '*') {
                                        do {
                                                c = getchar_update_lineno();
                                        } while (c == '*');
                                        if (c == '/')
                                                break;
                                }
                        }
                } else {
                        xungetc();
                        return '/';
                }
        }
}
static char *
read_token(void)
{
        int c, q;
        char *buf;
        unsigned int alc, off;
        char* delims = "(),{}";
        while (1) {
                c = getchar_skipping_comments();
                if (c == EOF)
                        return nil;
                if (!xisspace(c))
                        break;
        }
        alc = 16;
        buf = xmalloc(alc + 1);
        off = 0;
        if(c == '"' || c == '\'') {
                q = c;
                buf[off] = c;
                ++off;
                while (1) {
                        if (off+2 >= alc) { 
                                alc *= 2;
                                buf = xrealloc(buf, alc + 1);
                        }
                        c = getchar_no_eof();
                        buf[off] = c;
                        ++off;
                        if(c == q)
                                break;
                        if(c == '\\') {
                                buf[off] = getchar_no_eof();
                                ++off;
                        }
                }
        } else if (xstrrchr(delims, c) != nil) {
                buf[off] = c;
                ++off;
        } else {
                while (1) {
                        if (off >= alc) {
                                alc *= 2;
                                buf = xrealloc(buf, alc + 1);
                        }
                        buf[off] = c;
                        ++off;
                        c = getchar_skipping_comments();
                        if (c == EOF)
                                break;
                        if (xisspace(c) || xstrrchr(delims, c) != nil) {
                                if (c == '\n')
                                        lineno--;
                                xungetc();
                                break;
                        }
                }
        }
        buf[off] = '\0';
        return buf;
}
static char *
read_token_no_eof(void)
{
        char *token = read_token();
        if (token == nil)
                bad_eof();
        return token;
}
static char *
read_package(void)
{
        char *token;
        token = read_token_no_eof();
        if (token == nil)
                fatal("%s:%d: no token\n", file, lineno);
        if (!streq(token, "package")) {
                fatal("%s:%d: expected \"package\", got \"%s\"\n",
                        file, lineno, token);
        }
        return read_token_no_eof();
}
static void
read_preprocessor_lines(void)
{
        int first;
        
        first = 1;
        while (1) {
                int c;
                do {
                        c = getchar_skipping_comments();
                } while (xisspace(c));
                if (c != '#') {
                        xungetc();
                        break;
                }
                if(first) {
                        first = 0;
                        xputchar('\n');
                }
                xputchar(c);
                do {
                        c = getchar_update_lineno();
                        xputchar(c);
                } while (c != '\n');
        }
}
static char *
read_type(void)
{
        char *p, *op, *q;
        int pointer_count;
        unsigned int len;
        p = read_token_no_eof();
        if (*p != '*' && !streq(p, "int") && !streq(p, "uint"))
                return p;
        op = p;
        pointer_count = 0;
        while (*p == '*') {
                ++pointer_count;
                ++p;
        }
        len = xstrlen(p);
        q = xmalloc(len + 2 + pointer_count + 1);
        xmemmove(q, p, len);
        
        if((len == 3 && xmemcmp(q, "int", 3) == 0) || (len == 4 && xmemcmp(q, "uint", 4) == 0)) {
                q[len++] = 'g';
                q[len++] = 'o';
        }
        while (pointer_count-- > 0)
                q[len++] = '*';
        
        q[len] = '\0';
        xfree(op);
        return q;
}
static int
type_size(char *p, int *rnd)
{
        int i;
        if(p[xstrlen(p)-1] == '*') {
                *rnd = type_table[Uintptr].rnd;
                return type_table[Uintptr].size;
        }
        if(streq(p, "Iface"))
                p = "Eface";
        for(i=0; type_table[i].name; i++)
                if(streq(type_table[i].name, p)) {
                        *rnd = type_table[i].rnd;
                        return type_table[i].size;
                }
        fatal("%s:%d: unknown type %s\n", file, lineno, p);
        return 0;
}
static struct params *
read_params(int *poffset)
{
        char *token;
        struct params *ret, **pp, *p;
        int offset, size, rnd;
        ret = nil;
        pp = &ret;
        token = read_token_no_eof();
        offset = 0;
        if (!streq(token, ")")) {
                while (1) {
                        p = xmalloc(sizeof(struct params));
                        p->name = token;
                        p->next = nil;
                        *pp = p;
                        pp = &p->next;
                        if(streq(token, "...")) {
                                p->type = xstrdup("");
                        } else {
                                p->type = read_type();
                                rnd = 0;
                                size = type_size(p->type, &rnd);
                                if(rnd > structround)
                                        rnd = structround;
                                if(offset%rnd)
                                        offset += rnd - offset%rnd;
                                offset += size;
                        }
                        token = read_token_no_eof();
                        if (!streq(token, ","))
                                break;
                        token = read_token_no_eof();
                }
        }
        if (!streq(token, ")")) {
                fatal("%s:%d: expected '('\n",
                        file, lineno);
        }
        if (poffset != nil)
                *poffset = offset;
        return ret;
}
static int
read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
{
        int lastline;
        char *token;
        lastline = -1;
        while (1) {
                read_preprocessor_lines();
                token = read_token();
                if (token == nil)
                        return 0;
                if (streq(token, "func")) {
                        if(lastline != -1)
                                bwritef(output, "\n");
                        break;
                }
                if (lastline != lineno) {
                        if (lastline == lineno-1)
                                bwritef(output, "\n");
                        else
                                bwritef(output, "\n#line %d \"%s\"\n", lineno, file);
                        lastline = lineno;
                }
                bwritef(output, "%s ", token);
        }
        *name = read_token_no_eof();
        token = read_token();
        if (token == nil || !streq(token, "(")) {
                fatal("%s:%d: expected \"(\"\n",
                        file, lineno);
        }
        *params = read_params(paramwid);
        token = read_token();
        if (token == nil || !streq(token, "("))
                *rets = nil;
        else {
                *rets = read_params(nil);
                token = read_token();
        }
        if (token == nil || !streq(token, "{")) {
                fatal("%s:%d: expected \"{\"\n",
                        file, lineno);
        }
        return 1;
}
static void
write_params(struct params *params, int *first)
{
        struct params *p;
        for (p = params; p != nil; p = p->next) {
                if (*first)
                        *first = 0;
                else
                        bwritef(output, ", ");
                bwritef(output, "%s %s", p->type, p->name);
        }
}
static void
write_6g_func_header(char *package, char *name, struct params *params,
                     int paramwid, struct params *rets)
{
        int first, n;
        struct params *p;
        bwritef(output, "void\n");
        if(!contains(name, "·"))
                bwritef(output, "%s·", package);
        bwritef(output, "%s(", name);
        first = 1;
        write_params(params, &first);
        
        if(rets != nil && paramwid%structround != 0) {
                n = structround - paramwid%structround;
                if(n & 1)
                        bwritef(output, ", uint8");
                if(n & 2)
                        bwritef(output, ", uint16");
                if(n & 4)
                        bwritef(output, ", uint32");
        }
        write_params(rets, &first);
        bwritef(output, ")\n{\n");
        
        for (p = rets; p != nil; p = p->next) {
                if(streq(p->name, "..."))
                        continue;
                if(streq(p->type, "Slice"))
                        bwritef(output, "\t%s.array = 0;\n\t%s.len = 0;\n\t%s.cap = 0;\n", p->name, p->name, p->name);
                else if(streq(p->type, "String"))
                        bwritef(output, "\t%s.str = 0;\n\t%s.len = 0;\n", p->name, p->name);
                else if(streq(p->type, "Eface"))
                        bwritef(output, "\t%s.type = 0;\n\t%s.data = 0;\n", p->name, p->name);
                else if(streq(p->type, "Iface"))
                        bwritef(output, "\t%s.tab = 0;\n\t%s.data = 0;\n", p->name, p->name);
                else if(streq(p->type, "Complex128"))
                        bwritef(output, "\t%s.real = 0;\n\t%s.imag = 0;\n", p->name, p->name);
                else
                        bwritef(output, "\t%s = 0;\n", p->name);
                bwritef(output, "\tFLUSH(&%s);\n", p->name);
        }
}
static void
write_6g_func_trailer(struct params *rets)
{
        struct params *p;
        for (p = rets; p != nil; p = p->next)
                if(!streq(p->name, "..."))
                        bwritef(output, "\tFLUSH(&%s);\n", p->name);
        bwritef(output, "}\n");
}
static void
define_gcc_return_type(char *package, char *name, struct params *rets)
{
        struct params *p;
        if (rets == nil || rets->next == nil)
                return;
        bwritef(output, "struct %s_%s_ret {\n", package, name);
        for (p = rets; p != nil; p = p->next)
                bwritef(output, "  %s %s;\n", p->type, p->name);
        bwritef(output, "};\n");
}
static void
write_gcc_return_type(char *package, char *name, struct params *rets)
{
        if (rets == nil)
                bwritef(output, "void");
        else if (rets->next == nil)
                bwritef(output, "%s", rets->type);
        else
                bwritef(output, "struct %s_%s_ret", package, name);
}
static void
write_gcc_func_header(char *package, char *name, struct params *params,
                      struct params *rets)
{
        int first;
        struct params *p;
        define_gcc_return_type(package, name, rets);
        write_gcc_return_type(package, name, rets);
        bwritef(output, " %s_%s(", package, name);
        first = 1;
        write_params(params, &first);
        bwritef(output, ") asm (\"%s.%s\");\n", package, name);
        write_gcc_return_type(package, name, rets);
        bwritef(output, " %s_%s(", package, name);
        first = 1;
        write_params(params, &first);
        bwritef(output, ")\n{\n");
        for (p = rets; p != nil; p = p->next)
                bwritef(output, "  %s %s;\n", p->type, p->name);
}
static void
write_gcc_func_trailer(char *package, char *name, struct params *rets)
{
        if (rets == nil) {
                
        }
        else if (rets->next == nil)
                bwritef(output, "return %s;\n", rets->name);
        else {
                struct params *p;
                bwritef(output, "  {\n    struct %s_%s_ret __ret;\n", package, name);
                for (p = rets; p != nil; p = p->next)
                        bwritef(output, "    __ret.%s = %s;\n", p->name, p->name);
                bwritef(output, "    return __ret;\n  }\n");
        }
        bwritef(output, "}\n");
}
static void
write_func_header(char *package, char *name,
                  struct params *params, int paramwid,
                  struct params *rets)
{
        if (gcc)
                write_gcc_func_header(package, name, params, rets);
        else
                write_6g_func_header(package, name, params, paramwid, rets);
        bwritef(output, "#line %d \"%s\"\n", lineno, file);
}
static void
write_func_trailer(char *package, char *name,
                   struct params *rets)
{
        if (gcc)
                write_gcc_func_trailer(package, name, rets);
        else
                write_6g_func_trailer(rets);
}
static void
copy_body(void)
{
        int nesting = 0;
        while (1) {
                int c;
                c = getchar_no_eof();
                if (c == '}' && nesting == 0)
                        return;
                xputchar(c);
                switch (c) {
                default:
                        break;
                case '{':
                        ++nesting;
                        break;
                case '}':
                        --nesting;
                        break;
                case '/':
                        c = getchar_update_lineno();
                        xputchar(c);
                        if (c == '/') {
                                do {
                                        c = getchar_no_eof();
                                        xputchar(c);
                                } while (c != '\n');
                        } else if (c == '*') {
                                while (1) {
                                        c = getchar_no_eof();
                                        xputchar(c);
                                        if (c == '*') {
                                                do {
                                                        c = getchar_no_eof();
                                                        xputchar(c);
                                                } while (c == '*');
                                                if (c == '/')
                                                        break;
                                        }
                                }
                        }
                        break;
                case '"':
                case '\'':
                        {
                                int delim = c;
                                do {
                                        c = getchar_no_eof();
                                        xputchar(c);
                                        if (c == '\\') {
                                                c = getchar_no_eof();
                                                xputchar(c);
                                                c = '\0';
                                        }
                                } while (c != delim);
                        }
                        break;
                }
        }
}
static void
process_file(void)
{
        char *package, *name, *p, *n;
        struct params *params, *rets;
        int paramwid;
        package = read_package();
        read_preprocessor_lines();
        while (read_func_header(&name, ¶ms, ¶mwid, &rets)) {
                
                n = xstrstr(name, "·");
                if(n != nil) {
                        p = xmalloc(n - name + 1);
                        xmemmove(p, name, n - name);
                        p[n - name] = 0;
                        n += xstrlen("·");
                } else {
                        p = package;
                        n = name;
                }
                write_func_header(p, n, params, paramwid, rets);
                copy_body();
                write_func_trailer(p, n, rets);
                xfree(name);
                if(p != package) xfree(p);
                free_params(params);
                free_params(rets);
        }
        xfree(package);
}
void
goc2c(char *goc, char *c)
{
        int i;
        Buf in, out;
        
        binit(&in);
        binit(&out);
        
        file = goc;
        readfile(&in, goc);
        
        if(!gcc) {
                if(streq(goarch, "amd64")) {
                        type_table[Uintptr].size = 8;
                        if(use64bitint) {
                                type_table[Int].size = 8;
                        } else {
                                type_table[Int].size = 4;
                        }
                        structround = 8;
                } else if(streq(goarch, "amd64p32")) {
                        type_table[Uintptr].size = 4;
                        type_table[Int].size = 4;
                        structround = 8;
                } else {
                        
                        
                        
                        
                        type_table[Uintptr].size = 4;
                        type_table[Int].size = 4;
                        structround = 4;
                }
                type_table[Uint].size = type_table[Int].size;
                type_table[Slice].size = type_table[Uintptr].size+2*type_table[Int].size;
                type_table[Eface].size = 2*type_table[Uintptr].size;
                type_table[String].size = 2*type_table[Uintptr].size;
                for(i=0; i<nelem(type_table); i++)
                        type_table[i].rnd = type_table[i].size;
                type_table[String].rnd = type_table[Uintptr].rnd;
                type_table[Slice].rnd = type_table[Uintptr].rnd;
                type_table[Eface].rnd = type_table[Uintptr].rnd;
                type_table[Complex128].rnd = type_table[Float64].rnd;
        }
        bprintf(&out, "// auto generated by go tool dist\n// goos=%s goarch=%s\n\n", goos, goarch);
        input = bstr(&in);
        output = &out;
        lineno = 1;
        process_file();
        
        writefile(&out, c, 0);
}