refactor: clean and plugin tests (#26)

* refactor: remove gi_c
* refactor: new intergation example.
* chore: adds new targets.
* doc: adds issue template.
This commit is contained in:
Ludovic Fernandez
2019-01-22 15:53:52 +01:00
committed by Marc Vertes
parent 3c674c2cc4
commit 3f000e5fac
31 changed files with 118 additions and 2209 deletions

27
.github/ISSUE_TEMPLATE/Bug_report.md vendored Normal file
View File

@@ -0,0 +1,27 @@
---
name: Bug report
about: Create a report to help us improve
---
The following program `sample.go` triggers a panic:
```go
package main
func main() {
// add a sample
}
```
Expected result:
```console
$ go run ./sample.go
// ouput
```
Got:
```console
$ dyngo ./sample.go
// ouput
```

View File

@@ -13,4 +13,9 @@ gen_all_syscall: cmd/goexports/goexports
cmd/goexports/goexports: cmd/goexports/goexports.go
go generate cmd/goexports/goexports.go
.PHONY: check gen_all_syscall
gen_tests:
make -C _test
generate: gen_all_syscall cmd/goexports/goexports gen_tests
.PHONY: check gen_all_syscall gen_tests

View File

@@ -1,30 +0,0 @@
sys = $(shell uname -s)
CPPFLAGS ?= -Wall -Ideps/include
CFLAGS ?= -g
# Linux linker requires rpath set if lib is not in default path
Linux_LDFLAGS = -Wl,-rpath=$(CURDIR)/deps/lib
LDFLAGS ?= $($(sys)_LDFLAGS) -Ldeps/lib -llightning
all: deps gi l2 loop2
gi: gi.o graph.o hash.o init_go.o node.o parse_go.o run_cfg.o run_jit.o scan.o
l2: l2.go
go build -o l2 l2.go
loop2: loop2.go
go build -o loop2 loop2.go
test: gi
./gi -acx loop2.go
deps:
$(MAKE) -C deps
clean:
rm -f *.o gi loop2 l2
.PHONY: deps clean

View File

@@ -1,23 +0,0 @@
# gi_c
Proof of concept for a go interpreter, using previous private works
# Install
dependencies: graphviz for AST / CFG visualization
```
make
make test
```
# Notes
Language scope is very limited, just enough to run the demo script `loop2.go`. Interesting enough to get an idea of performances compared with binaries, with or without JIT compilation.
the machine code generator is using GNU-lightning (installed with `make deps`).
Do not expect many improvements here, the real work will take place in Go, and will try to reuse as much as possible existing Go assets.
--
Marc

View File

@@ -1,7 +0,0 @@
# Build and install dependencies
build:
for dep in *.makefile; do make -f $$dep build; done
clean:
for dep in *.makefile; do make -f $$dep clean; done

View File

@@ -1,24 +0,0 @@
# fetch, build and install a dependency
# Just include this file and provide URL variable with the source location
TGZ ?= $(notdir $(URL))
DIR ?= $(shell a=$(TGZ); echo $${a%.t*z})
DEST = $(CURDIR)
all: build
build: $(DIR)/.build_ok
clean:
rm -rf $(DIR)
$(DIR)/.build_ok: $(DIR)
cd $(DIR) && ./configure --prefix=$(DEST) && make && make install
touch $(DIR)/.build_ok
$(DIR): $(TGZ)
tar xvfz $(TGZ) || { rm -rf $(DIR); false; }
$(TGZ):
curl -L -o $@.tmp $(URL)
mv $@.tmp $@

View File

@@ -1,3 +0,0 @@
URL = http://ftp.gnu.org/gnu/lightning/lightning-2.1.2.tar.gz
include deps.mk

View File

@@ -1,135 +0,0 @@
/* a go interpreter */
#define VERSION "gi-c-0.1"
static const char man_txt[] =
"NAME\n"
" gi - go interpreter\n"
"SYNOPSIS\n"
" gi [-acnsVx] [-A ast_file] [-C cfg_file] [--] [script_file [args ...]]\n"
"DESCRIPTION\n"
" gi is an interpreter that executes commands read from a file or the\n"
" standard input.\n"
"OPTIONS\n"
" -A ast_file \n"
" Write the abstract syntax tree in dot(1) format to ast_file or\n"
" standard output if ast_file is -\n"
" -a Display AST graph using dotty(1)\n"
" -C cfg_file \n"
" Write the control flow graph in dot(1) format to cfg_file or\n"
" standard output if cfg_file is -\n"
" -c Display CFG graph using dotty(1)\n"
" -n Compile only, do not run\n"
" -x Generate and execute machine code using a JIT compiler\n"
" -v Trace each instruction during execution\n"
" -V Print interpreter version and exit\n"
"BIP LANGUAGE\n"
" Commands are read in terms of lines of words separated by whitespaces\n"
" (blanks or tabs) and certain sequences of characters called ``operators''.\n"
" commands may also be separated by ';' or grouped between braces into a\n"
" list\n"
" OPERATORS\n"
" Bip uses the usual infix notation for operators (example: c = a + b).\n"
" Precedence rules identical to C are applied. Parenthesis are used to\n"
" group expression and make precedence explicit.\n"
" + - * / % \n"
" Arithmetic: addition, substraction, multiplication, division\n"
" and modulo.\n"
" < <= > >= == != \n"
" Comparison: lower, lower or equal, greater, greater or equal,\n"
" equal, not equal.\n"
" ! && || \n"
" Logical: not, and, or.\n"
" = Assignement.\n"
" << >> & | \n"
" Binary: left shift, right shift, boolean and, boolean or.\n"
" FLOW CONTROL\n"
" if cond list1 [else list0] \n"
" the cond is executed and if it returns a non zero value, list1\n"
" is executed. Otherwise, if defined, list0 is executed.\n"
" while cond list \n"
" cond and list are repeatedly executed while cond returns non zero.\n"
"AUTHORS\n"
" MV\n"
;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "init_go.h"
#include "trace.h"
#define MSIZE 4096
int source_stream(bip_t *ip, FILE *fd)
{
int len = 0, max = 0;
char *src = NULL;
while (len == max) { /* Grow src buffer until everything is read */
max += MSIZE;
src = (char *)realloc(src, max);
len += fread(src + len, 1, MSIZE, fd);
}
src[len] = 0;
eval_str(ip, NULL, src, len);
printf("%s", ip->out);
ip->out[0] = 0;
free(src);
return len;
}
int main(int argc, char *argv[], char *env[])
{
int opt;
bip_t *ip = bip_init(0);
FILE *fd;
while ((opt = getopt(argc, argv, "A:aC:chnpVvx")) != -1) {
switch (opt) {
case 'A':
ip->fd_ast = strcmp(optarg, "-") ?
fopen(optarg, "w") : stdout;
break;
case 'a':
ip->opt.a = 1;
break;
case 'C':
ip->fd_cfg = strcmp(optarg, "-") ?
fopen(optarg, "w") : stdout;
break;
case 'c':
ip->opt.c = 1;
break;
case 'h':
printf("%s", man_txt);
exit(0);
case 'n':
ip->opt.n = 1;
break;
case 'p':
ip->opt.p = 1;
break;
case 'v':
ip->opt.v = 1;
break;
case 'V':
printf("%s\n", VERSION);
exit(0);
case 'x':
ip->opt.x = 1;
break;
default:
fprintf(stderr, "Usage: b1 [-acnVvx] [-A astname] "
"[-C fgname] [file]\n");
exit(1);
}
}
fd = ((argc - optind) > 0) ? fopen(argv[optind], "r") : stdin;
if (fd == NULL)
return 1;
while (source_stream(ip, fd));
return 0;
}

View File

@@ -1,87 +0,0 @@
/*
* Generate a serial control flow graph from an abstract syntax tree
*/
#include <stdlib.h>
#include "node.h"
#include "trace.h"
static node_t *add_cond_branch(bip_t *ip, node_t *n)
{
node_t *node = (node_t *)calloc(1, sizeof(node_t));
node->type = COND_BRANCH;
node->num = ++ip->nc;
node->pv = n->pv;
node->sym = getsym(ip, "CB", 2);
node->f = node->sym->f;
return node;
}
static void cfg_out(bip_t *ip, node_t *node, void *data)
{
int i;
node_t *n;
switch ((int)node->type) {
case FUN: case OP: case OPS: case SL:
for (i = 0; i < node->nchild; i++) {
if (!is_leaf(node->child[i])) {
node->start = node->child[i]->start;
break;
}
}
if (!node->start)
node->start = node;
for (i = 1; i < node->nchild; i++) {
node->child[i-1]->snext = node->child[i]->start;
}
for (i = node->nchild - 1; i >= 0; i--) {
if (!is_leaf(node->child[i])) {
node->child[i]->snext = node;
break;
}
}
break;
case IF:
node->start = node->child[0]->start;
node->child[1]->snext = node;
if (node->nchild == 3) {
node->child[2]->snext = node;
}
n = add_cond_branch(ip, node->child[0]);
node->child[0]->snext = n;
n->next[TRUE] = node->child[1]->start;
if (node->nchild == 3) {
n->next[FALSE] = node->child[2]->start;
} else {
n->next[FALSE] = node;
}
break;
case WHILE:
node->start = node->child[0]->start;
node->child[1]->snext = node->start;
n = add_cond_branch(ip, node->child[0]);
node->child[0]->snext = n;
n->next[TRUE] = node->child[1]->start;
n->next[FALSE] = node;
break;
case FOR:
node->start = node->child[0]->start;
node->child[0]->snext = node->child[1]->start;
n = add_cond_branch(ip, node->child[1]);
node->child[1]->snext = n;
n->next[TRUE] = node->child[3]->start;
n->next[FALSE] = node;
node->child[3]->snext = node->child[2]->start;
node->child[2]->snext = node->child[1]->start;
break;
default:
; //t_s(nodetype[node->type]);
}
}
void ast2cfg(bip_t *ip, node_t *node)
{
tree_walk(ip, node, NULL, cfg_out, NULL);
addentry(ip, node->start);
}

View File

@@ -1,8 +0,0 @@
#ifndef GRAPH_H
#define GRAPH_H
#include "node.h"
void ast2cfg(bip_t *ip, node_t *node);
#endif /* GRAPH_H */

View File

@@ -1,102 +0,0 @@
#include <stdlib.h>
#include "hash.h"
hash_t *hinit(unsigned int n, cmpfun_t cmpf)
{
hash_t *h = (hash_t *)malloc(sizeof(hash_t));
h->htab = (hitem_t **)calloc(n, sizeof(hitem_t *));
h->cmpf = cmpf;
h->len = n;
h->nhash = 0;
return h;
}
static void hresize(hash_t *h, unsigned int n)
{
unsigned int i, j;
hitem_t *p, *pp, **tab = (hitem_t **)calloc(n, sizeof(hitem_t *));
for (i = 0; i < h->len; i++) {
p = h->htab[i];
while (p) {
pp = p->next;
j = p->key % n;
p->next = tab[j];
tab[j] = p;
p = pp;
}
}
free(h->htab);
h->htab = tab;
h->len = n;
}
unsigned int hkey(char *s)
{
unsigned int h = 0;
while (*s)
h = h * 31 + *s++;
return h;
}
unsigned int hnkey(const char *s, int n, unsigned int h)
{
while (n--)
h = h * 31 + *s++;
return h;
}
void *hadd(hash_t *h, unsigned int key, void *index, void *data)
{
hitem_t *p;
unsigned int i;
if (h->nhash >= h->len && h->len < HNITEM_MAX)
hresize(h, h->len * 2);
p = (hitem_t *)malloc(sizeof(hitem_t));
i = key < h->len ? key : key % h->len;
p->key = key;
p->data = data;
p->index = index;
p->next = h->htab[i];
h->htab[i] = p;
h->nhash++;
return data;
}
void *hdel(hash_t *h, hitem_t *item)
{
unsigned int i = item->key % h->len;
hitem_t *p = h->htab[i];
void *data = item->data;
if (p == item) {
h->htab[i] = p->next;
goto del;
}
for (; p; p = p->next)
if (p->next == item) {
p->next = p->next->next;
goto del;
}
return (void *)-1;
del: h->nhash--;
free(item);
return data;
}
void *hlookup(hash_t *h, unsigned int key, void *data, int len)
{
hitem_t *p;
unsigned int i = key < h->len ? key : key % h->len;
for (p = h->htab[i]; p; p = p->next) {
if (p->key == key) {
if (data && h->cmpf && (*h->cmpf)(data, p->data, len))
continue; /* key collision */
else
return p->data;
}
}
return NULL;
}

View File

@@ -1,37 +0,0 @@
#ifndef HASH_H
#define HASH_H
/* hash item */
typedef struct hitem_t {
struct hitem_t *next; /* next item in same slot */
void *index; /* pointer to index data */
void *data; /* pointer to value data */
unsigned int key; /* hash key, obtained from index */
} hitem_t;
/* key hash comparison function type */
typedef int (*cmpfun_t)(void *, void *, int);
/* dynamically resizable array / hash table */
typedef struct hash_t {
hitem_t **htab; /* hash slots */
cmpfun_t cmpf; /* user provided key comparison function */
unsigned int len; /* tab size */
unsigned int nhash; /* number of hashed items */
} hash_t;
/* hash table iterator */
#define hforeach(h, i, c) \
for (c = 0; (unsigned int)c < (h)->len; c++) \
for (i = (h)->htab[c]; i; i = i->next)
#define HNITEM_MAX ((unsigned)(1 << (8 * sizeof(int) -1))) /* 2^31 on 32 bit */
hash_t *hinit(unsigned int n, cmpfun_t cmpf);
unsigned int hkey(char *s);
unsigned int hnkey(const char *s, int n, unsigned int h);
void *hadd(hash_t *h, unsigned int key, void *index, void *data);
void *hdel(hash_t *h, hitem_t *item);
void *hlookup(hash_t *h, unsigned int key, void *data, int len);
#endif /* HASH_H */

View File

@@ -1,133 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "graph.h"
#include "node.h"
#include "parse_go.h"
#include "run_cfg.h"
#include "run_jit.h"
#include "scan.h"
#define X4_scan_bad scan_bad, scan_bad, scan_bad, scan_bad
#define X16_scan_bad X4_scan_bad, X4_scan_bad, X4_scan_bad, X4_scan_bad
#define X64_scan_bad X16_scan_bad, X16_scan_bad, X16_scan_bad, X16_scan_bad
/* BIP language lexical table */
static const scan_fun_t scanfun[256] = {
scan_bad, scan_bad, scan_bad, scan_bad, scan_bad, // NUL SOH STX ETX EOT
scan_bad, scan_bad, scan_bad, scan_bad, scan_wsep, // ENQ ACQ BELL BS HT
scan_csep, scan_bad, scan_bad, scan_csep, scan_bad, // LF VT FF CR SO
scan_bad, scan_bad, scan_bad, scan_bad, scan_bad, // SI DLE DC1 DC2 DC3
scan_bad, scan_bad, scan_bad, scan_bad, scan_bad, // DC4 NAK SYN ETB CAN
scan_bad, scan_bad, scan_bad, scan_bad, scan_bad, // EM SUB ESC FS GS
scan_bad, scan_bad, scan_wsep, scan_go_op, scan_str, // RS US ' ' ! "
scan_cmt, scan_go_op, scan_go_op, scan_go_op, scan_go_op, // # $ % & '
scan_paren, scan_bad, scan_go_op, scan_go_op, scan_lsep, // ( ) * + ,
scan_go_op, scan_go_op, scan_go_op, scan_num, scan_num, // - . / 0 1
scan_num, scan_num, scan_num, scan_num, scan_num, // 2 3 4 5 6
scan_num, scan_num, scan_num, scan_go_op, scan_csep, // 7 8 9 : ;
scan_go_op, scan_go_op, scan_go_op, scan_go_op, scan_go_op, // < = > ? @
scan_id, scan_id, scan_id, scan_id, scan_id, // A B C D E
scan_id, scan_id, scan_id, scan_id, scan_id, // F G H I J
scan_id, scan_id, scan_id, scan_id, scan_id, // K L M N O
scan_id, scan_id, scan_id, scan_id, scan_id, // P Q R S T
scan_id, scan_id, scan_id, scan_id, scan_id, // U V W X Y
scan_id, scan_bracket, scan_bad, scan_bad, scan_go_op, // Z [ \ ] ^
scan_id, scan_go_op, scan_id, scan_id, scan_id, // _ ` a b c
scan_id, scan_id, scan_id, scan_id, scan_id, // d e f g h
scan_id, scan_id, scan_id, scan_id, scan_id, // i j k l m
scan_id, scan_id, scan_id, scan_id, scan_id, // n o p q r
scan_id, scan_id, scan_id, scan_id, scan_id, // s t u v w
scan_id, scan_id, scan_id, scan_brace, scan_go_op, // x y z { |
scan_bad, scan_go_op, scan_bad, // } ~ DEL
X64_scan_bad, X64_scan_bad // Non ASCII
};
static int cmpsym(void *data, void *sym, int n)
{
return strncmp((char *)data, ((sym_t *)sym)->name, n);
}
bip_t *bip_init(int trace_opt)
{
bip_t *ip = (bip_t *)calloc(1, sizeof(*ip));
ip->scanfun = (scan_fun_t *)scanfun;
ip->gsym = hinit(64, cmpsym);
ip->lsym = hinit(16, cmpsym);
newsym(ip->gsym, "if", IF, 0, nop, j_nop);
newsym(ip->gsym, "break", BREAK, 0, NULL, j_nop);
newsym(ip->gsym, "continue", CONTINUE, 0, NULL, j_nop);
newsym(ip->gsym, "for", FOR, 0, nop, j_nop);
newsym(ip->gsym, "func", DEF, 0, NULL, j_nop);
newsym(ip->gsym, "return", RETURN, 0, NULL, j_nop);
newsym(ip->gsym, "local", LOCAL, 0, NULL, j_nop);
newsym(ip->gsym, "eval", FUN, 0, NULL, j_nop);
newsym(ip->gsym, "print", FUN, 0, NULL, j_nop);
newsym(ip->gsym, "println", FUN, 0, echo, j_echo);
newsym(ip->gsym, "source", FUN, 0, NULL, j_nop);
newsym(ip->gsym, "dsym", FUN, 0, NULL, j_nop);
newsym(ip->gsym, "map", FUN, 0, NULL, j_nop);
newsym(ip->gsym, "nop", OP, 0, nop, j_nop);
newsym(ip->gsym, "SL", SL, 0, nop, j_nop);
newsym(ip->gsym, "CB", COND_BRANCH, 0, cond_branch, j_nop);
newsym(ip->gsym, "package", NAMESPACE, 0, nop, j_nop);
newsym(ip->gsym, "++", OPS, 0, inc, j_inc);
newsym(ip->gsym, "--", OPS, 0, NULL, j_nop);
newsym(ip->gsym, "!", OP, 10, NULL, j_not);
newsym(ip->gsym, "+", OP, 8, add, j_add);
newsym(ip->gsym, "-", OP, 8, sub, j_sub);
newsym(ip->gsym, "~", OP, 10, NULL, j_nop);
newsym(ip->gsym, "^", OP, 10, NULL, j_xor);
newsym(ip->gsym, "*", OP, 9, mul, j_mul);
newsym(ip->gsym, "/", OP, 9, fdiv, j_div);
newsym(ip->gsym, "%", OP, 9, mod, j_rem);
newsym(ip->gsym, "<", OP, 6, lt, j_lt);
newsym(ip->gsym, "<=", OP, 6, le, j_le);
newsym(ip->gsym, ">=", OP, 6, ge, j_ge);
newsym(ip->gsym, ">", OP, 6, gt, j_gt);
newsym(ip->gsym, "==", OP, 5, eq, j_eq);
newsym(ip->gsym, "!=", OP, 5, neq, j_ne);
newsym(ip->gsym, ":=", OP, 0, assign, j_assign);
newsym(ip->gsym, "=", OP, 0, assign, j_assign);
newsym(ip->gsym, "&&", OP, 2, NULL, j_land);
newsym(ip->gsym, "||", OP, 1, NULL, j_lor);
newsym(ip->gsym, "&", OP, 4, band, j_and);
newsym(ip->gsym, "|", OP, 3, bor, j_or);
newsym(ip->gsym, "<<", OP, 7, lshift, j_lsh);
newsym(ip->gsym, ">>", OP, 7, rshift, j_rsh);
ip->out = (char *)calloc(1, 1024);
ip->opt.x = trace_opt;
return ip;
}
node_t *eval_str(bip_t *ip, node_t *node, char *s, int len)
{
node_t *n = parse_sl(ip, &s, &len);
if (n->nchild == 0)
return node;
if (ip->fd_ast)
print_tree(ip, ip->fd_ast, n);
if (ip->opt.a)
dotty(ip, n, print_tree);
n = n->child[1]->child[2];
ast2cfg(ip, n);
if (ip->fd_cfg)
print_flow(ip, ip->fd_cfg, n);
if (ip->opt.c)
dotty(ip, n, print_flow);
if (ip->opt.x)
run_jit(ip, n);
else if (!ip->opt.n) {
run_cfg(ip);
}
return node ? node : n;
}
void bip_eval(bip_t *ip, char *s, char **res)
{
eval_str(ip, NULL, s, strlen(s));
*res = ip->out;
}

View File

@@ -1,9 +0,0 @@
#ifndef INIT_H
#define INIT_H
#include "node.h"
bip_t *bip_init(int trace_opt);
node_t *eval_str(bip_t *ip, node_t *node, char *s, int len);
#endif /* INIT_H */

View File

@@ -1,9 +0,0 @@
package main
func main() {
for a := 0; a < 20000; a++ {
if (a & 0x8ff) == 0x800 {
println(a)
}
}
}

View File

@@ -1,9 +0,0 @@
package main
func main() {
for a := 0; a < 20000000; a++ {
if (a & 0x8ffff) == 0x80000 {
println(a)
}
}
}

View File

@@ -1,9 +0,0 @@
package main
func main() {
for a := 0; a < 2000000000; a++ {
if (a & 0x8ffff) == 0x80000 {
println(a)
}
}
}

View File

@@ -1,247 +0,0 @@
/* generic node utility functions */
#include <stdlib.h>
#include <string.h>
#include "node.h"
#include "trace.h"
/* Maintain the following in consistency with enum nodetype_t */
const char *nodetype[NODETYPE_LEN] = {
"UNDEF", "SL", "IF", "WHILE", "BREAK", "CONTINUE", "DEF", "FOR",
"RETURN", "LOCAL", "MAP", "OPS", "OP", "TERM", "VAR", "FUN",
"LVAR", "ARRAY", "COND_BRANCH", "NAMESPACE"
};
/* Recursive implementation of tree walk, depth first */
void tree_walk(bip_t *ip, node_t *node, tw_fun_t in, tw_fun_t out, void *data)
{
int i;
if (in)
in(ip, node, data);
for (i = 0; node && i < node->nchild; i++)
tree_walk(ip, node->child[i], in, out, data);
if (out)
out(ip, node, data);
}
/* Non recursive tree walk */
void new_tree_walk(bip_t *ip, node_t *node, tw_fun_t in, tw_fun_t out, void *data)
{
ip->cur = node;
if (in)
in(ip, ip->cur, NULL);
while (1) {
++ip->cur->visits;
if (ip->cur->nchild > 0 && ip->cur->visits <= ip->cur->nchild) {
ip->cur = ip->cur->child[ip->cur->visits - 1];
if (in)
in(ip, ip->cur, NULL);
} else {
ip->cur->visits = 0;
if (out)
out(ip, ip->cur, NULL);
if (ip->cur == node)
break;
else
ip->cur = ip->cur->anc;
}
}
}
/* append child node to the list of anc children node */
void appchild(node_t *anc, node_t *child)
{
if (child == NULL) {
//t_s("nil child");
return;
}
anc->child = (node_t **)realloc(anc->child,
++anc->nchild * sizeof(node_t *));
anc->child[anc->nchild - 1] = child;
child->anc = anc;
}
/* insert child node at first position in anc children list */
void inschild(node_t *anc, node_t *child)
{
node_t **ochild = anc->child;
int onchild = anc->nchild, i;
anc->nchild = 0;
anc->child = NULL;
appchild(anc, child);
for (i = 0; i < onchild; i++)
appchild(anc, ochild[i]);
free(ochild);
}
void delchild(node_t *anc, node_t *child)
{
node_t **ochild = anc->child;
int onchild = anc->nchild, i;
anc->nchild = 0;
anc->child = NULL;
for (i = 0; i < onchild; i++)
if (ochild[i] != child)
appchild(anc, ochild[i]);
free(ochild);
}
void print_val(FILE *fd, val_t *pv, int quote)
{
switch ((int)pv->type) {
case VINT:
fprintf(fd, "%ld", pv->u.num);
break;
case VFLOAT:
fprintf(fd, "%g", pv->u.fnum);
break;
case VSTR:
if (quote == 0)
fprintf(fd, "\\\"%s\\\"", pv->u.str);
else if (quote == 2)
fprintf(fd, "\"%s\"", pv->u.str);
else
fprintf(fd, "%s", pv->u.str);
break;
default:
break;
}
}
void print_node_label(FILE *fd, node_t *node, int flow)
{
switch ((int)node->type) {
case TERM:
fprintf(fd, " %d: ", node->num);
//fprintf(fd, " ");
print_val(fd, node->pv, flow);
break;
case SL:
fprintf(fd, " %d: %s", node->num, nodetype[node->type]);
//fprintf(fd, " %s", nodetype[node->type]);
break;
case VAR:
fprintf(fd, " %d: %s", node->num, node->sym->name);
//fprintf(fd, " %s", node->sym->name);
break;
default:
if (flow)
fprintf(fd, " $%d:", node->num);
//fprintf(fd, " ");
else
if (node->sym)
fprintf(fd, " %d: %s", node->num, node->sym->name);
//fprintf(fd, " %s", node->sym->name);
else
fprintf(fd, " %d: undefined", node->num);
break;
}
}
static void pnode(bip_t *ip, node_t *node, void *data)
{
FILE *fd = (FILE *)data;
fprintf(fd, "%d [type=\"%s\", label=\"", node->num,
nodetype[node->type]);
print_node_label(fd, node, 0);
fprintf(fd, "\"]\n");
if (node->anc)
fprintf(fd, "%d -> %d\n", node->anc->num, node->num);
}
void print_tree(bip_t *ip, FILE *fd, node_t *node)
{
fprintf(fd, "digraph ast {\n");
tree_walk(ip, node, pnode, NULL, fd);
fprintf(fd, "}\n");
}
static void pflow(bip_t *ip, node_t *node, void *data)
{
int i, start = 0;
FILE *fd = (FILE *)data;
if (node == NULL || node->type == TERM || node->type == VAR ||
node->type == BREAK || node->type == CONTINUE)
return;
fprintf(fd, "%d [label=\"%d:", node->num, node->num);
if (node->type == OP) {
print_node_label(fd, node->child[0], 1);
start = 1;
}
print_node_label(fd, node, 0);
for (i = start; i < node->nchild; i++)
print_node_label(fd, node->child[i], 1);
fprintf(fd, "\"]\n");
if (!node->snext)
return;
if (node->snext->next[TRUE]) {
fprintf(fd, "%d -> %d [color=green]\n", node->num,
node->snext->next[TRUE]->num);
}
if (node->snext->next[FALSE]) {
fprintf(fd, "%d -> %d [color=red]\n", node->num,
node->snext->next[FALSE]->num);
}
if (!node->snext->next[TRUE] && !node->snext->next[FALSE]) {
fprintf(fd, "%d -> %d\n", node->num, node->snext->num);
}
}
void print_flow(bip_t *ip, FILE *fd, node_t *node)
{
int i;
fprintf(fd, "digraph cfg {\n");
tree_walk(ip, node, NULL, pflow, fd);
for (i = 0; i < ip->nentry_points; i++)
fprintf(fd, "%d [color=red]", ip->entry_points[i]->num);
fprintf(fd, "}\n");
}
void dotty(bip_t *ip, node_t *node, dotty_fun_t dotty_fun)
{
FILE *fd = popen("dotty -", "w");
if (fd == NULL) {
perror("dotty");
return;
}
dotty_fun(ip, fd, node);
fflush(fd);
//getchar();
}
/* Add a new entry (start of thread) for parallel execution */
void addentry(bip_t *ip, node_t *node)
{
ip->entry = (node_t **)realloc(ip->entry, ++ip->nentry * sizeof(node));
ip->entry[ip->nentry - 1] = node;
}
/* Add node at end of list, increase list_len */
void appnode(node_t ***list, node_t *node, int *list_len)
{
*list = (node_t **)realloc(*list, ++(*list_len) * sizeof(node));
(*list)[*list_len - 1] = node;
}
sym_t *newsym(hash_t *h, const char *s, nodetype_t type, int prio, fun_t ifun,
fun_t cfun)
{
sym_t *sym = (sym_t *)calloc(1, sizeof(*sym));
sym->name = (char *)s;
sym->type = type;
sym->prio = prio;
sym->f = ifun;
sym->jf = cfun;
return (sym_t *)hadd(h, hkey(sym->name), sym->name, sym);
}
sym_t *getsym(bip_t *ip, const char *s, int len)
{
unsigned int key = hnkey(s, len, 0);
return (sym_t *)hlookup(ip->gsym, key, (void *)s, len);
}

View File

@@ -1,140 +0,0 @@
#ifndef NODE_H
#define NODE_H
#include <pthread.h>
#include <stdio.h>
#include "hash.h"
#include "scan.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define UP 0
#define DOWN 1
#define RD 0
#define WR 1
// types which could be part of expressions must be defined after OP
typedef enum nodetype_t {
UNDEF, SL, IF, WHILE, BREAK, CONTINUE, DEF, FOR, RETURN, LOCAL, MAP, OPS,
OP, TERM, VAR, FUN, LVAR, ARRAY, COND_BRANCH, NAMESPACE,
NODETYPE_LEN
} nodetype_t;
// String version of above, for debug
extern const char *nodetype[NODETYPE_LEN];
typedef enum valtype_t {
VINT, VSTR, VFUN, VTAB, VPTR, VFLOAT, VSYM, VVAR, VPINT, VPFLOAT,
VVOID, VSHORT, VQUAD, VBIN
} valtype_t;
typedef struct bip_t bip_t;
typedef struct node_t node_t;
typedef void (*fun_t)(node_t *n);
typedef struct jit_node jit_node_t; /* from lightning.h */
typedef struct val_t {
int len;
valtype_t type; /* type of following field */
union {
long num; /* integer value */
double fnum; /* floating point value */
char *str; /* string value */
void *data; /* user data value */
// unsigned char *bin; /* binary data */
// struct sym_t *sym; /* symbol value */
// fun_t fun; /* function value */
} u;
} val_t;
typedef struct sym_t {
char *name; /* symbol unique name */
nodetype_t type; /* symbol type */
int prio; /* operator priority */
node_t *assign; /* node which sets this symbol */
val_t v; /* data value */
fun_t f; /* function to run during execution */
fun_t jf; /* jit compiler callback */
node_t **access[2];
int naccess[2];
int reg; /* jit register number */
} sym_t;
struct node_t {
node_t *anc; /* unique ancestor */
node_t **child; /* array of children */
sym_t *sym; /* symbol (variable, function, op) */
nodetype_t type;
int num; /* unique serial number */
int nchild; /* number of children */
int prio; /* operator precedence (from sym) */
val_t v; /* value during execution */
val_t *pv; /* pointer on above or sym value */
fun_t f; /* function to run during execution */
int visits; /* Number of node visits for non rec tree_walk */
node_t *start; /* entry point in subtree (CFG) */
node_t *snext; /* next node to eval (CFG) */
node_t *next[2]; /* false and true branches in CFG */
jit_node_t *label; /* label to jump to (JIT) */
int reg; /* register number (JIT) */
};
/* Interpreter state, used during compilation and execution */
struct bip_t {
scan_fun_t *scanfun; /* lexical scanner table of functions */
hash_t *gsym; /* parse: global hashed symbol table */
hash_t *lsym; /* parse: local hashed symbol table */
node_t *root;
node_t *cur;
node_t *prev;
node_t **entry; /* run: array of entry points */
int nentry; /* number of entry points (threads) */
int nc; /* node counter */
int last_direction;
node_t *fork_node; /* To replace jump stack */
node_t *ctx_node; /* context ID */
node_t **entry_points;
int nentry_points;
node_t *global_fork_node;
struct {
unsigned int a : 1; /* AST option */
unsigned int c : 1; /* CFG option */
unsigned int n : 1; /* no-run option */
unsigned int p : 1; /* parallel option */
unsigned int v : 1; /* trace option */
unsigned int x : 1; /* native exec option */
} opt;
FILE *fd_ast; /* file to write AST */
FILE *fd_cfg; /* file to write CFG */
char *out;
int outlen;
pthread_mutex_t outm;
};
#define is_leaf(node) ((node)->type == TERM || (node)->type == VAR)
typedef void (*tw_fun_t)(bip_t *, node_t *, void *data);
typedef void (*dotty_fun_t)(bip_t *ip, FILE *fd, node_t *node);
void tree_walk(bip_t *ip, node_t *node, tw_fun_t in, tw_fun_t out, void *data);
void new_tree_walk(bip_t *ip, node_t *node, tw_fun_t in, tw_fun_t out, void *data);
void appchild(node_t *anc, node_t *child);
void inschild(node_t *anc, node_t *child);
void delchild(node_t *anc, node_t *child);
void print_val(FILE *fd, val_t *pv, int quote);
void print_node_label(FILE *fd, node_t *node, int flow);
void print_tree(bip_t *ip, FILE *fd, node_t *node);
void print_flow(bip_t *ip, FILE *fd, node_t *node);
void dotty(bip_t *ip, node_t *node, dotty_fun_t dotty_fun);
void addentry(bip_t *ip, node_t *node);
void appnode(node_t ***list, node_t *node, int *list_len);
sym_t *newsym(hash_t *h, const char *s, nodetype_t type, int prio, fun_t ifun, fun_t cfun);
sym_t *getsym(bip_t *ip, const char *s, int len);
#endif /* NODE_H */

View File

@@ -1,278 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "node.h"
#include "scan.h"
#include "run_cfg.h"
#include "trace.h"
static node_t *parse_1(bip_t *ip, char **pstr, int *plen);
static node_t *parse_statement(bip_t *ip, char **pstr, int *plen);
node_t *parse_sl(bip_t *ip, char **pstr, int *plen);
static char *strdupn(char *str, int len)
{
char *s = (char *)malloc(len + 1);
strncpy(s, str, len);
s[len] = '\0';
return s;
}
static node_t *parse_int(bip_t *ip, scan_t *ps, char **pstr, int *plen)
{
node_t *node = (node_t *)calloc(1, sizeof(node_t));
node->type = TERM;
node->num = ++ip->nc;
node->pv = &node->v;
node->pv->type = VINT;
node->pv->u.num = ps->num;
return node;
}
static node_t *parse_float(bip_t *ip, scan_t *ps, char **pstr, int *plen)
{
node_t *node = (node_t *)calloc(1, sizeof(node_t));
node->type = TERM;
node->num = ++ip->nc;
node->pv = &node->v;
node->pv->type = VFLOAT;
node->pv->u.fnum = ps->fnum;
return node;
}
static node_t *parse_str(bip_t *ip, scan_t *ps, char **pstr, int *plen)
{
node_t *node = (node_t *)calloc(1, sizeof(node_t));
node->type = TERM;
node->num = ++ip->nc;
node->pv = &node->v;
node->pv->type = VSTR;
node->pv->len = ps->len;
node->pv->u.str = strdupn(ps->tok, ps->len);
return node;
}
static node_t *parse_parenthesis(bip_t *ip, scan_t *ps, char **pstr, int *plen)
{
node_t *node = (node_t *)calloc(1, sizeof(node_t));
node->num = ++ip->nc;
node->type = SL;
node->pv = &node->v;
appchild(node, parse_statement(ip, &ps->tok, &ps->len));
return node;
}
static node_t *parse_paren(bip_t *ip, scan_t *ps, char **pstr, int *plen)
{
node_t *node = parse_statement(ip, &ps->tok, &ps->len);
node->prio = 20; // override precedence
return node;
}
static node_t *parse_bracket(bip_t *ip, scan_t *ps, char **pstr, int *plen)
{
node_t *node = (node_t *)calloc(1, sizeof(node_t));
node->num = ++ip->nc;
node->type = ARRAY;
appchild(node, parse_statement(ip, &ps->tok, &ps->len));
return node;
}
static node_t *parse_oper(bip_t *ip, scan_t *ps, char **pstr, int *plen)
{
node_t *node = (node_t *)calloc(1, sizeof(node_t));
node->num = ++ip->nc;
node->pv = &node->v;
if ((node->sym = getsym(ip, ps->tok, ps->len))) {
node->type = node->sym->type;
node->f = node->sym->f;
}
if (node->type != OPS)
appchild(node, parse_1(ip, pstr, plen));
return node;
}
static node_t *parse_id(bip_t *ip, scan_t *ps, char **pstr, int *plen)
{
node_t *node = (node_t *)calloc(1, sizeof(node_t)), *n;
scan_t sc;
char *s;
int l;
node->num = ++ip->nc;
if ((node->sym = getsym(ip, ps->tok, ps->len))) {
node->type = node->sym->type;
} else {
node->type = VAR;
node->sym = newsym(ip->gsym, strdupn(ps->tok, ps->len),
VAR, 0, nop, NULL);
}
node->f = node->sym->f;
switch ((int)node->sym->type) {
case NAMESPACE:
appchild(node, parse_1(ip, pstr, plen));
break;
case DEF:
// FIXME: handle all variants of DEF
// function name
appchild(node, parse_1(ip, pstr, plen));
// function args
l = *plen;
s = *pstr;
scan(ip->scanfun, &sc, &s, &l);
appchild(node, parse_parenthesis(ip, &sc, pstr, plen));
*pstr = s;
*plen = l;
// function body
appchild(node, parse_1(ip, pstr, plen));
break;
case FOR:
// FIXME: handle all variants of FOR
appchild(node, parse_statement(ip, pstr, plen));
appchild(node, parse_statement(ip, pstr, plen));
appchild(node, parse_statement(ip, pstr, plen));
appchild(node, parse_statement(ip, pstr, plen));
break;
case IF:
appchild(node, parse_statement(ip, pstr, plen));
appchild(node, parse_statement(ip, pstr, plen));
s = *pstr;
l = *plen;
scan(ip->scanfun, &sc, &s, &l);
if (sc.type == ID && sc.len == 4 &&
strncmp(sc.tok, "else", 4) == 0) {
*pstr = s;
*plen = l;
appchild(node, parse_statement(ip, pstr, plen));
}
break;
case OP:
appchild(node, parse_1(ip, pstr, plen));
break;
case RETURN:
appchild(node, parse_statement(ip, pstr, plen));
break;
case FUN:
node->pv = &node->v;
while ((n = parse_1(ip, pstr, plen)))
appchild(node, n);
break;
case VAR:
node->pv = &node->sym->v;
s = *pstr;
l = *plen;
scan(ip->scanfun, &sc, &s, &l);
if (sc.type == OPER) {
sym_t *sym = getsym(ip, sc.tok, sc.len);
if (sym && sym->type == OPS) {
n = parse_1(ip, pstr, plen);
appchild(n, node);
node = n;
}
}
break;
default:
t_s(nodetype[node->sym->type]);
break;
}
return node;
}
static node_t *parse_brace(bip_t *ip, scan_t *ps, char **pstr, int *plen)
{
return parse_sl(ip, &ps->tok, &ps->len);
}
static node_t *parse_bad(bip_t *ip, scan_t *ps, char **pstr, int *plen)
{
return NULL;
}
typedef node_t *(*parse_fun_t) (bip_t *, scan_t *, char **, int *);
// Table indiced by scan_token_t
static const parse_fun_t parse_fun[] = {
parse_bad, parse_brace, parse_bracket, parse_bad, parse_bad,
parse_float, parse_id, parse_int, parse_bad, parse_oper,
parse_paren, parse_str,
};
/* Return a single node, possibly a complex subtree. */
static node_t *parse_1(bip_t *ip, char **pstr, int *plen)
{
scan_t sc;
scan(ip->scanfun, &sc, pstr, plen);
return parse_fun[sc.type](ip, &sc, pstr, plen);
}
/* Return a statement node. Apply operator precedence rules (reordering nodes). */
static node_t *parse_statement(bip_t *ip, char **pstr, int *plen)
{
scan_t sc = {};
char *s = *pstr;
int len = *plen;
node_t *first = NULL, *node = NULL, *n, *n1;
start:
while (len > 0 && scan(ip->scanfun, &sc, &s, &len) != CSEP) {
if (first && sc.type == BRACE) {
unscan(&sc, &s, &len);
break;
}
node = parse_fun[sc.type](ip, &sc, &s, &len);
if (!first) {
first = node;
} else if (node->type == OP) {
node->prio = node->sym->prio;
for (n = first; n; n = n->nchild > 1 ? n->child[1] : NULL) {
if (n->type != OP || node->prio <= n->prio
|| (n->type == OP && n->nchild == 1)) {
if (n == first) {
first = node;
} else {
n1 = n->anc;
delchild(n1, n);
appchild(n1, node);
}
inschild(node, n);
break;
}
}
} else {
unscan(&sc, &s, &len);
break;
}
// If node is a kind of statement not part of an expression, stop here
if (node->type < OP)
break;
}
if (!first) {
// FIXME: handle parse error
if (len > 0 && sc.type == CSEP) {
(*pstr)++;
(*plen)--;
goto start;
}
//t_s(scan_token[sc.type]);
}
*pstr = s;
*plen = len;
return first;
}
/* Return a statement list node */
node_t *parse_sl(bip_t *ip, char **pstr, int *plen)
{
node_t *node = (node_t *)calloc(1, sizeof(node_t));
node->type = SL;
node->num = ++ip->nc;
node->sym = getsym(ip, "SL", 2);
node->f = node->sym->f;
while (*plen > 0)
appchild(node, parse_statement(ip, pstr, plen));
return node;
}

View File

@@ -1,8 +0,0 @@
#ifndef PARSE_GO_HH
#define PARSE_GO_HH
#include "node.h"
node_t *parse_sl(bip_t *ip, char **pstr, int *plen);
#endif /* PARSE_GO_H */

View File

@@ -1,186 +0,0 @@
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "node.h"
#include "trace.h"
#define FALSE 0
#define TRUE 1
void nop(node_t *n)
{
return;
}
void assign(node_t *n)
{
*n->pv = *n->child[0]->pv = *n->child[1]->pv;
}
void cond_branch(node_t *n)
{
n->snext = n->pv->u.num ? n->next[TRUE] : n->next[FALSE];
}
void inc(node_t *n)
{
n->child[0]->pv->u.num++;
}
void bprintf_val(val_t *pv)
{
switch((int)pv->type) {
case VINT:
printf("%ld", pv->u.num);
break;
case VFLOAT:
printf("%g", pv->u.fnum);
case VSTR:
printf("%s", pv->u.str);
default:
break;
}
}
void bprint_val(bip_t *ip, val_t *pv, int quote)
{
char s[100];
switch ((int)pv->type) {
case VINT:
snprintf(s, sizeof(s), "%ld", pv->u.num);
break;
case VFLOAT:
snprintf(s, sizeof(s), "%g", pv->u.fnum);
break;
case VSTR:
snprintf(s, sizeof(s), "%s", pv->u.str);
break;
if (quote == 0)
snprintf(s, sizeof(s), "\\\"%s\\\"", pv->u.str);
else if (quote == 2)
snprintf(s, sizeof(s), "\"%s\"", pv->u.str);
else
snprintf(s, sizeof(s), "%s", pv->u.str);
break;
default:
break;
}
strcat(ip->out, s);
}
void bprint_node_label(bip_t *ip, node_t *node, int flow)
{
char s[100];
switch ((int)node->type) {
case TERM:
strcat(ip->out, " ");
bprint_val(ip, node->pv, flow);
break;
case SL:
snprintf(s, sizeof(s), " %s", nodetype[node->type]);
strcat(ip->out, s);
break;
case VAR:
snprintf(s, sizeof(s), " %s", node->sym->name);
strcat(ip->out, s);
break;
default:
if (flow)
snprintf(s, sizeof(s), " $%d", node->num);
else
snprintf(s, sizeof(s), " %s", node->sym->name);
strcat(ip->out, s);
break;
}
}
void echo(node_t *n)
{
int i;
for (i = 0; i < n->nchild; i++)
bprintf_val(n->child[i]->pv);
printf("\n");
//bprint_val(ip, n->child[i]->pv, 1);
//strcat(ip->out, "\n");
}
void trace(FILE *fd, bip_t *ip, node_t *node, int tid)
{
int i, start = 0;
char s[100];
if (node->sym->f == nop || node->type == SL)
return;
snprintf(s, sizeof(s), "[%d] $%d:", tid, node->num);
strcat(ip->out, s);
if (node->type == OP) {
bprint_node_label(ip, node->child[0], 2);
start = 1;
}
bprint_node_label(ip, node, 0);
for (i = start; i < node->nchild; i++)
bprint_node_label(ip, node->child[i], 2);
strcat(ip->out, ": ");
bprint_val(ip, node->pv, 2);
strcat(ip->out, "\n");
}
void run_cfg(bip_t *ip)
{
node_t *n = ip->entry[0];
while (n) {
n->f(n);
n = n->snext;
}
}
#define define_arithmetic_opfun(name, op) \
void name(node_t *n) \
{ \
val_t *v0, *v1; \
const static val_t v = {0}; \
if (n->nchild == 1) { \
v0 = (val_t *)&v; \
v1 = n->child[0]->pv; \
} else { \
v0 = n->child[0]->pv; \
v1 = n->child[1]->pv; \
} \
n->pv->u.num = v0->u.num op v1->u.num; \
}
#define define_comparison_opfun(name, op) \
void name(node_t *n) \
{ \
n->pv->u.num = n->child[0]->pv->u.num op n->child[1]->pv->u.num;\
}
#define define_bitwise_opfun(name, op) \
void name(node_t *n) \
{ \
n->pv->u.num = n->child[0]->pv->u.num op n->child[1]->pv->u.num;\
}
/* Generate code for common operators */
#define check_zero_div(v) \
{if (v == 0) fprintf(stderr, "run error: divide by zero\n"); return;}
define_arithmetic_opfun(fdiv, /)
#undef check_zero_div
#define check_zero_div(v)
define_arithmetic_opfun(add, +)
define_arithmetic_opfun(sub, -)
define_arithmetic_opfun(mul, *)
define_bitwise_opfun(band, &)
define_bitwise_opfun(bor, |)
define_bitwise_opfun(lshift, <<)
define_bitwise_opfun(rshift, >>)
define_bitwise_opfun(mod, %)
define_comparison_opfun(eq, ==)
define_comparison_opfun(neq, !=)
define_comparison_opfun(ge, >=)
define_comparison_opfun(gt, >)
define_comparison_opfun(le, <=)
define_comparison_opfun(lt, <)

View File

@@ -1,30 +0,0 @@
#ifndef RUN_CFG_H
#define RUN_CFG_H
#include "node.h"
void nop(node_t *n);
void assign(node_t *n);
void echo(node_t *n);
void cond_branch(node_t *n);
void inc(node_t *n);
void add(node_t *n);
void sub(node_t *n);
void mul(node_t *n);
void fdiv(node_t *n);
void band(node_t *n);
void bor(node_t *n);
void lshift(node_t *n);
void rshift(node_t *n);
void mod(node_t *n);
void eq(node_t *n);
void neq(node_t *n);
void ge(node_t *n);
void gt(node_t *n);
void le(node_t *n);
void lt(node_t *n);
void run_cfg(bip_t *ip);
#endif /* RUN_CFG_H */

View File

@@ -1,313 +0,0 @@
/* jit runtime for bip */
#include <stdio.h>
#include <lightning.h>
#include "node.h"
#include "run_jit.h"
#include "trace.h"
typedef struct reg_t {
sym_t *sym; /* symbol associated to register */
} reg_t;
static reg_t regs[JIT_V_NUM];
static jit_state_t *_jit; /* XXX: should be in bip_t */
static inline void load(int reg, node_t *n)
{
if (n->type == VAR)
n->reg = n->sym->reg;
if (n->reg) {
if (reg != n->reg)
jit_movr(reg, n->reg);
} else if (n->type == TERM)
jit_movi(reg, n->pv->u.num);
else if (reg != JIT_R0)
jit_movr(reg, JIT_R0);
//else if (0)
// jit_ldi(reg, &n->pv->u.num);
}
static inline int is_if_cond(node_t *n)
{
return (n->anc && n->anc->type == IF && n->anc->child[0] == n);
}
static inline int is_for_cond(node_t *n)
{
return (n->anc && n->anc->type == FOR && n->anc->child[1] == n);
}
static inline int is_while_cond(node_t *n)
{
return (n->anc && n->anc->type == WHILE && n->anc->child[0] == n);
}
static inline int is_cond(node_t *n)
{
return is_if_cond(n) || is_for_cond(n) || is_while_cond(n);
}
static int regalloc(sym_t *sym)
{
int i;
if (sym->reg)
return sym->reg; /* already allocated */
for (i = 0; i < JIT_V_NUM; i++) {
if (regs[i].sym == NULL) {
regs[i].sym = sym;
sym->reg = JIT_V(i);
jit_ldi(sym->reg, &sym->v.u.num);
return i;
}
}
return 0;
}
void j_assign(node_t *n)
{
sym_t *var = n->child[0]->sym;
if (regalloc(var)) {
n->reg = n->child[0]->reg = var->reg;
load(n->reg, n->child[1]);
} else {
load(JIT_R0, n->child[1]);
jit_sti(&n->child[0]->pv->u.num, JIT_R0);
}
return;
}
static int gen_branch(node_t *n, int r1)
{
jit_node_t **plabel;
node_t *c1;
if (!is_cond(n))
return 0;
plabel = (n->anc->nchild == 3) ?
&n->anc->child[2]->label :
&n->anc->label;
c1 = n->child[1];
if (n->sym->jf == j_eq) {
*plabel = (c1->type == TERM) ?
jit_bnei(r1, c1->pv->u.num) :
jit_bner(r1, c1->reg);
} else if (n->sym->jf == j_ne) {
*plabel = (c1->type == TERM) ?
jit_beqi(r1, c1->pv->u.num) :
jit_beqr(r1, c1->reg);
} else if (n->sym->jf == j_le) {
*plabel = (c1->type == TERM) ?
jit_bgti(r1, c1->pv->u.num) :
jit_bgtr(r1, c1->reg);
} else if (n->sym->jf == j_gt) {
*plabel = (c1->type == TERM) ?
jit_blei(r1, c1->pv->u.num) :
jit_bler(r1, c1->reg);
} else if (n->sym->jf == j_lt) {
*plabel = (c1->type == TERM) ?
jit_bgei(r1, c1->pv->u.num) :
jit_bger(r1, c1->reg);
} else if (n->sym->jf == j_ge) {
*plabel = (c1->type == TERM) ?
jit_blti(r1, c1->pv->u.num) :
jit_bltr(r1, c1->reg);
} else {
t_s(n->sym->name);
*plabel = jit_beqi(r1, 0);
}
return 1;
}
#define define_binary_operator(name) \
void j_##name(node_t *n) \
{ \
int r0, r1; \
if (n->anc->type == VAR) \
n->reg = n->anc->reg = n->anc->sym->reg; \
else if (n->anc->type == OP && n->anc->sym->jf == j_assign) \
n->reg = n->anc->reg = n->anc->child[0]->sym->reg; \
if (n->child[0]->type == VAR) \
n->child[0]->reg = n->child[0]->sym->reg; \
if (n->child[1]->type == VAR) \
n->child[1]->reg = n->child[1]->sym->reg; \
r0 = n->anc->reg; \
r1 = n->child[0]->reg; \
load(r1, n->child[0]); \
if (gen_branch(n, r1)) \
return; \
if (n->child[1]->reg) { \
jit_##name##r(r0, r1, JIT_V(n->child[1]->reg)); \
} else if (n->child[1]->type == TERM) { \
jit_##name##i(r0, r1, n->child[1]->pv->u.num); \
} else { \
jit_##name##r(r0, r1, JIT_R0); \
} \
if (0) jit_sti(&n->pv->u.num, JIT_V(n->anc->reg)); \
}
define_binary_operator(add) /* c0 + c1 */
define_binary_operator(sub) /* c0 - c1 */
define_binary_operator(mul) /* c0 * c1 */
define_binary_operator(div) /* c0 / c1 */
define_binary_operator(rem) /* c0 % c1 */
define_binary_operator(lt) /* c0 < c1 */
define_binary_operator(le) /* c0 <= c1 */
define_binary_operator(eq) /* c0 == c1 */
define_binary_operator(ne) /* c0 != c1 */
define_binary_operator(gt) /* c0 > c1 */
define_binary_operator(ge) /* c0 >= c1 */
define_binary_operator(and) /* c0 & c1 */
define_binary_operator(or) /* c0 | c1 */
define_binary_operator(xor) /* c0 ^ c1 */
define_binary_operator(lsh) /* c0 << c1 */
define_binary_operator(rsh) /* c0 >> c1 */
#define define_unary_operator(name) \
void j_##name(node_t *n) \
{ \
jit_ldi(JIT_V0, &n->child[0]->pv->u.num); \
jit_##name##r(JIT_V0, JIT_V0); \
jit_sti(&n->pv->u.num, JIT_V0); \
}
define_unary_operator(neg)
define_unary_operator(com)
static void do_echo_i(int i)
{
printf("%d\n", i);
}
void j_echo(node_t *n)
{
jit_prepare();
load(JIT_R0, n->child[0]);
jit_pushargr(JIT_R0);
jit_finishi((jit_pointer_t)do_echo_i);
}
void j_land(node_t *n)
{
load(JIT_R0, n->child[0]);
n->label = jit_beqi(JIT_R0, 0);
load(JIT_R0, n->child[1]);
jit_patch(n->label);
}
void j_lor(node_t *n)
{
load(JIT_R0, n->child[0]);
n->label = jit_bnei(JIT_R0, 0);
load(JIT_R0, n->child[1]);
jit_patch(n->label);
}
void j_nop(node_t *n)
{
return;
}
void j_inc(node_t *n)
{
// Avoid costly (and useless in loops) load/store between memory and register
//jit_ldi(JIT_V0, &n->child[0]->pv->u.num);
//jit_addi(JIT_V0, JIT_V0, 1);
//jit_sti(&n->child[0]->pv->u.num, JIT_V0);
int reg = n->child[0]->sym->reg;
jit_addi(reg, reg, 1);
}
void j_not(node_t *n)
{
load(JIT_R0, n->child[0]);
jit_eqi(JIT_R0, JIT_R0, 0);
jit_sti(&n->pv->u.num, JIT_R0);
}
/* code generated by postorder traveral of the abstract syntax tree */
static void code_generation(bip_t *ip, node_t *n, void *data)
{
node_t *anc = n->anc;
if (is_leaf(n)) {
if (is_cond(n)) {
load(JIT_R0, n);
if (anc->nchild == 3)
anc->child[2]->label = jit_beqi(JIT_R0, 0);
else
anc->label = jit_beqi(JIT_R0, 0);
}
return;
}
if (n->label)
jit_patch(n->label);
if (is_for_cond(n))
n->label = jit_label();
if (is_while_cond(n))
n->label = jit_label();
n->sym->jf(n);
if (anc == NULL)
return;
if (anc->type == IF) {
if (anc->child[1] == n) { /* in true block */
if (anc->nchild == 3)
anc->child[1]->label = jit_jmpi();
} else if (anc->nchild == 3 && anc->child[2] == n) { /* in false block */
jit_patch_at(n->anc->child[1]->label, jit_label());
}
} else if (anc->type == FOR) {
if (anc->child[3] == n) /* in true block */
jit_patch_at(jit_jmpi(), anc->child[1]->label);
} else if (anc->type == WHILE) {
if (anc->child[1] == n) /* in true block */
jit_patch_at(jit_jmpi(), anc->child[0]->label);
}
}
/* compute necessary space for stack allocation, tag nodes using stack */
static void stack_analysis(bip_t *ip, node_t *n, void *data)
{
if (n->type == OP) {
t_s(n->sym->name);
if (!is_leaf(n->child[0])) {
t_d(n->num);
t_d(ip->prev->num);
t_d(n->child[0]->num);
t_s(n->child[0]->sym->name);
}
if (!is_leaf(n->child[1])) {
t_d(n->num);
t_d(ip->prev->num);
t_d(n->child[1]->num);
t_s(n->child[1]->sym->name);
}
}
ip->prev = n;
}
void run_jit(bip_t *ip, node_t *node)
{
void (*func)(void);
init_jit("b1");
_jit = jit_new_state();
jit_prolog();
tree_walk(ip, node, NULL, stack_analysis, NULL);
tree_walk(ip, node, NULL, code_generation, NULL);
jit_epilog();
func = (void (*)(void))jit_emit();
if (ip->opt.v) {
jit_print();
jit_disassemble();
}
if (!ip->opt.n)
func();
finish_jit();
}

View File

@@ -1,36 +0,0 @@
#ifndef RUN_JIT_H
#define RUN_JIT_H
#include "node.h"
void j_assign(node_t *n);
void j_echo(node_t *n);
void j_nop(node_t *n);
void j_inc(node_t *n);
void j_add(node_t *n); /* c0 + c1 */
void j_sub(node_t *n); /* c0 - c1 */
void j_mul(node_t *n); /* c0 * c1 */
void j_div(node_t *n); /* c0 / c1 */
void j_rem(node_t *n); /* c0 % c1 */
void j_lt(node_t *n); /* c0 < c1 */
void j_le(node_t *n); /* c0 <= c1 */
void j_eq(node_t *n); /* c0 == c1 */
void j_ne(node_t *n); /* c0 != c1 */
void j_gt(node_t *n); /* c0 > c1 */
void j_ge(node_t *n); /* c0 >= c1 */
void j_and(node_t *n); /* c0 & c1 */
void j_or(node_t *n); /* c0 | c1 */
void j_xor(node_t *n); /* c0 ^ c1 */
void j_lsh(node_t *n); /* c0 << c1 */
void j_rsh(node_t *n); /* c0 >> c1 */
void j_land(node_t *n); /* c0 && c1 */
void j_lor(node_t *n); /* c0 || c1 */
void j_neg(node_t *n);
void j_com(node_t *n);
void j_not(node_t *n); /* ! c0 */
void run_jit(bip_t *ip, node_t *node);
#endif /* RUN_JIT_H */

View File

@@ -1,232 +0,0 @@
/* scanner: lexical analysis functions */
/*
* Todo:
* - line counting
* - better error reporting
*/
#include <stdlib.h>
#include "scan.h"
#include "trace.h"
/* scan_token strings for debug. Keep in sync with scan_token_t in scan.h */
const char *scan_token[SCAN_TOKEN_LEN] = {
"BAD", "BRACE", "BRACKET", "BSTR", "CSEP", "FLOAT", "ID", "INT", "LSEP",
"OPER", "PAREN", "STR"
};
#define isdigit(c) ('0' <= (c) && (c) <= '9')
#define isalpha(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z'))
#define isalnum(c) (isdigit((c)) || isalpha((c)))
/* Return a pointer on the first occurence of char c in string s of length len */
static char *strnchr(char *s, int len, char c)
{
int i;
for (i = 0; i < len; i++)
if (s[i] == c)
return &s[i];
return NULL;
}
/* Flat scan of block delimited by i.e (), [], or {} */
int scan_block(scan_t *ps, char *s, scan_token_t type, int len, char bstart, char bend, char sdelim)
{
char c;
int complete = 0, inquote = 0, level = 0;
ps->tok = ++s;
c = *s;
while (len--) {
if (c == sdelim)
inquote = 1 - inquote;
else if (inquote && c == '\\')
s++;
else if (!inquote && c == bstart)
level++;
else if (!inquote && c == bend) {
if (--level < 0) {
complete = 1;
break;
}
}
c = *++s;
}
ps->type = complete ? type : BAD;
ps->end = s + 1;
ps->len = ps->end - ps->tok -1;
return 0;
}
int scan_paren(scan_t *ps, char *s, int len)
{
return scan_block(ps, s, PAREN, len, '(', ')', '"');
}
int scan_brace(scan_t *ps, char *s, int len)
{
return scan_block(ps, s, BRACE, len, '{', '}', '"');
}
int scan_bracket(scan_t *ps, char *s, int len)
{
return scan_block(ps, s, BRACKET, len, '[', ']', '"');
}
int scan_cmt(scan_t *ps, char *s, int len)
{
char c, *smax = s + len;
for (c = *++s; s < smax && c != '\n'; c = *++s);
ps->end = s;
return 1;
}
int scan_num(scan_t *ps, char *s, int len)
{
ps->fnum = strtod(s, &ps->end);
ps->tok = s;
ps->len = ps->end - ps->tok;
if (strnchr(ps->tok, ps->len, '.'))
ps->type = FLOAT;
else {
if (ps->tok[0] == '0' && ps->tok[1] != 'x')
ps->num = strtol(ps->tok, &ps->end, 8);
else
ps->num = (long)ps->fnum;
ps->type = INT;
}
return 0;
}
int scan_id(scan_t *ps, char *s, int len)
{
char c, *smax = s + len;
ps->tok = s;
ps->type = ID;
for (c = *++s; s < smax; c = *++s)
if (!(isalnum(c) || c == '_')) /* XXX could be accelerated */
break;
ps->end = s;
ps->len = s - ps->tok;
return 0;
}
int scan_wsep(scan_t *ps, char *s, int len)
{
char c, *smax = s + len;
for (c = *++s; s < smax; c = *++s) {
if (c != ' ' && c != '\t')
break;
}
ps->end = s;
return 1;
}
int scan_lsep(scan_t *ps, char *s, int len)
{
ps->type = LSEP;
ps->end = s + 1;
return 0;
}
int scan_csep(scan_t *ps, char *s, int len)
{
char c = *s, *smax = s + len;
for (c = *++s; s < smax; c = *++s)
if (c != '\n' && c != ';' && c != ' ' && c != '\t')
break;
ps->type = CSEP;
ps->end = s;
return 0;
}
int scan_str(scan_t *ps, char *s, int len)
{
char *smax = s + len, c, delim = *s;
ps->type = STR;
ps->tok = ++s;
for (c = *ps->tok; s < smax; c = *++s)
if (c == '\\')
s++, ps->type = BSTR;
else if (c == delim)
break;
if (s == smax && c != delim)
ps->type = BAD;
ps->len = s - ps->tok;
ps->end = s + 1;
return 0;
}
int scan_c_op(scan_t *ps, char *s, int len)
{
ps->tok = s;
ps->type = OPER;
switch (*s) {
case '!': if (s[1] == '=') s++; break;
case '=': if (s[1] == '=') s++; break;
case '<': if (s[1] == '=' || s[1] == '<') s++; break;
case '>': if (s[1] == '=' || s[1] == '>') s++; break;
case '&': if (s[1] == '&') s++; break;
case '|': if (s[1] == '|') s++; break;
case '+': if (s[1] == '+') s++; break;
case '-': if (s[1] == '-') s++; break;
}
ps->end = s + 1;
ps->len = ps->end - ps->tok;
return 0;
}
int scan_go_op(scan_t *ps, char *s, int len)
{
ps->tok = s;
ps->type = OPER;
switch (*s) {
case ':': if (s[1] == '=') s++; break;
case '!': if (s[1] == '=') s++; break;
case '=': if (s[1] == '=') s++; break;
case '<': if (s[1] == '=' || s[1] == '<') s++; break;
case '>': if (s[1] == '=' || s[1] == '>') s++; break;
case '&': if (s[1] == '&') s++; break;
case '|': if (s[1] == '|') s++; break;
case '+': if (s[1] == '+') s++; break;
case '-': if (s[1] == '-') s++; break;
}
ps->end = s + 1;
ps->len = ps->end - ps->tok;
return 0;
}
/* return a bad token */
int scan_bad(scan_t *ps, char *s, int len)
{
t_c(*s);
ps->tok = s;
ps->end = s + 1;
ps->type = BAD;
return 0;
}
/* scanner entry point */
int scan(scan_fun_t *scanfun, scan_t *ps, char **pstr, int *plen)
{
char *s = *pstr, *smax = s + *plen;
ps->orig = s;
ps->len = 0;
ps->type = BAD;
while (s < smax && (*scanfun[(int)*s])(ps, s, *plen))
s = ps->end;
*plen += *pstr - ps->end;
*pstr = ps->end;
return ps->type;
}
/* undo scan operation, revert to previous state */
void unscan(scan_t *ps, char **pstr, int *plen)
{
*pstr = ps->orig;
*plen += ps->end - ps->orig;
}

View File

@@ -1,47 +0,0 @@
#ifndef SCAN_H
#define SCAN_H
/* token types recognized by the scanner. For block operators, the
* opening char is used.
*/
typedef enum scan_token_t {
BAD, BRACE, BRACKET, BSTR, CSEP, FLOAT, ID, INT, LSEP, OPER, PAREN, STR,
SCAN_TOKEN_LEN
} scan_token_t;
/* strings of above for debug */
extern const char *scan_token[SCAN_TOKEN_LEN];
/* scanner state */
typedef struct scan_t {
char *tok; /* token start position in input */
char *end; /* next position in input */
char *orig; /* previous position */
scan_token_t type; /* token type */
int len; /* token len */
long num; /* scanner returned value if type is INT */
double fnum; /* scanner returned value if type is FLOAT */
} scan_t;
typedef int (*scan_fun_t)(scan_t *ps, char *s, int len);
int scan_block(scan_t *ps, char *s, scan_token_t type, int len, char bstart, char bend, char sdelim);
int scan_paren(scan_t *ps, char *s, int len);
int scan_brace(scan_t *ps, char *s, int len);
int scan_bracket(scan_t *ps, char *s, int len);
int scan_cmt(scan_t *ps, char *s, int len);
int scan_num(scan_t *ps, char *s, int len);
int scan_id(scan_t *ps, char *s, int len);
int scan_wsep(scan_t *ps, char *s, int len);
int scan_lsep(scan_t *ps, char *s, int len);
int scan_csep(scan_t *ps, char *s, int len);
int scan_str(scan_t *ps, char *s, int len);
int scan_c_op(scan_t *ps, char *s, int len);
int scan_go_op(scan_t *ps, char *s, int len);
int scan_bad(scan_t *ps, char *s, int len);
int scan(scan_fun_t *scanfun, scan_t *ps, char **pstr, int *plen);
void unscan(scan_t *ps, char **pstr, int *plen);
#endif /* SCAN_H */

View File

@@ -1,23 +0,0 @@
#ifndef TRACE_H
#define TRACE_H
#include <stdio.h>
/* Macros for temporary internal debug traces */
#define _tr(fmt, type, exp) fprintf(stderr, "[%s:%d %s] %s: " fmt, __FILE__,\
__LINE__, __func__, #exp, (type)(exp))
#define t_c(s) _tr("'%c'\n", char, s)
#define t_d(s) _tr("%ld\n", long int, s)
#define t_g(s) _tr("%g\n", double, s)
#define t_i(s) _tr("%d\n", int, s)
#define t_p(s) _tr("%p\n", void *, s)
#define t_s(s) _tr("'%s'\n", char *, s)
#define t_u(s) _tr("%lu\n", unsigned long int, s)
#define t_x(s) _tr("0x%lx\n", unsigned long int, s)
#define t_v(exp) {fprintf(stderr, "[%s:%d %s] %s\n", __FILE__, __LINE__, __func__, #exp); (void)(exp);}
#define t_sn(s, n) do { \
fprintf(stderr, "[%s:%d %s] %s: '", __FILE__, __LINE__, __func__, #s); \
fwrite((s), (n), 1, stderr); fputs("'\n", stderr); } while (0)
#endif /* TRACE_H */

View File

@@ -11,7 +11,7 @@ var version = "v1"
type Sample struct{ Name string }
// Handler is a Sample method to processes HTTP requests
func (s *Sample) Handler(w http.ResponseWriter, r *http.Request) {
func (s *Sample) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Welcome to my website", s.Name, version)
}
@@ -19,11 +19,12 @@ func (s *Sample) Handler(w http.ResponseWriter, r *http.Request) {
func NewSample(name string) func(http.ResponseWriter, *http.Request) {
s := &Sample{"test"}
fmt.Println("in NewSample", name, version, s)
return s.Handler
return s.ServeHTTP
}
//func main() {
// s := &Sample{"Test"}
// http.HandleFunc("/", s.Handler)
// http.ListenAndServe(":8080", nil)
//}
// NewSampleHandler returns a new sample handler function
func NewSampleHandler(name string) http.Handler {
s := &Sample{"test"}
fmt.Println("in NewSample", name, version, s)
return s
}

View File

@@ -0,0 +1,77 @@
package main
import (
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"testing"
"github.com/containous/dyngo/interp"
"github.com/containous/dyngo/stdlib"
)
func TestPlugin(t *testing.T) {
log.SetFlags(log.Lshortfile) // Debug: print source file locations in log output
// Init go interpreter
i := interp.New(interp.Opt{})
i.Use(stdlib.Value, stdlib.Type) // Use binary standard library
// Load plugin from sources
if _, err := i.Eval(`import "github.com/containous/dyngo/example/test_plugin/plugin"`); err != nil {
t.Fatal(err)
}
// Obtain a HTTP handler from the plugin
value, err := i.Eval(`plugin.NewSample("test")`)
if err != nil {
t.Fatal(err)
}
handler := value.Interface().(func(http.ResponseWriter, *http.Request))
mux := http.NewServeMux()
mux.HandleFunc("/", handler)
server := httptest.NewServer(mux)
defer server.Close()
resp, err := http.DefaultClient.Get(server.URL)
if err != nil {
t.Fatal(err)
}
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
expected := "Welcome to my website test v1\n"
if string(bytes) != expected {
t.Errorf("Got %s, want %s", string(bytes), expected)
}
}
func TestPluginMethod(t *testing.T) {
log.SetFlags(log.Lshortfile) // Debug: print source file locations in log output
// Init go interpreter
i := interp.New(interp.Opt{})
i.Use(stdlib.Value, stdlib.Type) // Use binary standard library
// Load plugin from sources
if _, err := i.Eval(`import "github.com/containous/dyngo/example/test_plugin/plugin"`); err != nil {
t.Fatal(err)
}
// Obtain a HTTP handler from the plugin
value, err := i.Eval(`plugin.NewSampleHandler("test")`)
if err != nil {
t.Fatal(err)
}
if _, ok := value.Interface().(http.Handler); ok {
t.Fatal("methods can be used, it's not possible")
}
}

View File

@@ -1,36 +0,0 @@
package main
import (
"log"
"net/http"
"github.com/containous/dyngo/interp"
"github.com/containous/dyngo/stdlib"
)
// This program starts an interpreter which loads a plugin to handle HTTP requests
func main() {
log.SetFlags(log.Lshortfile) // Debug: print source file locations in log output
// Init go interpreter
i := interp.New(interp.Opt{})
i.Use(stdlib.Value, stdlib.Type) // Use binary standard library
// Load plugin from sources
if _, err := i.Eval(`import "github.com/containous/dyngo/example/test_plugin/plugin"`); err != nil {
log.Fatal(err)
}
// Obtain a HTTP handler from the plugin
value, err := i.Eval(`plugin.NewSample("test")`)
if err != nil {
log.Fatal(err)
}
handler := value.Interface().(func(http.ResponseWriter, *http.Request))
http.HandleFunc("/", handler)
if err = http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}