Files
veejay/sandbox/veejay-current/libgoom/goomsl.c
Niels Elburg 90197d342b move stuff
git-svn-id: svn://code.dyne.org/veejay/trunk@1132 eb8d1916-c9e9-0310-b8de-cf0c9472ead5
2008-11-01 03:31:40 +00:00

1510 lines
45 KiB
C

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "goomsl.h"
#include "goomsl_private.h"
#include "goomsl_yacc.h"
/*#define TRACE_SCRIPT*/
/* {{{ definition of the instructions number */
#define INSTR_SETI_VAR_INTEGER 1
#define INSTR_SETI_VAR_VAR 2
#define INSTR_SETF_VAR_FLOAT 3
#define INSTR_SETF_VAR_VAR 4
#define INSTR_NOP 5
/* #define INSTR_JUMP 6 */
#define INSTR_SETP_VAR_PTR 7
#define INSTR_SETP_VAR_VAR 8
#define INSTR_SUBI_VAR_INTEGER 9
#define INSTR_SUBI_VAR_VAR 10
#define INSTR_SUBF_VAR_FLOAT 11
#define INSTR_SUBF_VAR_VAR 12
#define INSTR_ISLOWERF_VAR_VAR 13
#define INSTR_ISLOWERF_VAR_FLOAT 14
#define INSTR_ISLOWERI_VAR_VAR 15
#define INSTR_ISLOWERI_VAR_INTEGER 16
#define INSTR_ADDI_VAR_INTEGER 17
#define INSTR_ADDI_VAR_VAR 18
#define INSTR_ADDF_VAR_FLOAT 19
#define INSTR_ADDF_VAR_VAR 20
#define INSTR_MULI_VAR_INTEGER 21
#define INSTR_MULI_VAR_VAR 22
#define INSTR_MULF_VAR_FLOAT 23
#define INSTR_MULF_VAR_VAR 24
#define INSTR_DIVI_VAR_INTEGER 25
#define INSTR_DIVI_VAR_VAR 26
#define INSTR_DIVF_VAR_FLOAT 27
#define INSTR_DIVF_VAR_VAR 28
/* #define INSTR_JZERO 29 */
#define INSTR_ISEQUALP_VAR_VAR 30
#define INSTR_ISEQUALP_VAR_PTR 31
#define INSTR_ISEQUALI_VAR_VAR 32
#define INSTR_ISEQUALI_VAR_INTEGER 33
#define INSTR_ISEQUALF_VAR_VAR 34
#define INSTR_ISEQUALF_VAR_FLOAT 35
/* #define INSTR_CALL 36 */
/* #define INSTR_RET 37 */
/* #define INSTR_EXT_CALL 38 */
#define INSTR_NOT_VAR 39
/* #define INSTR_JNZERO 40 */
#define INSTR_SETS_VAR_VAR 41
#define INSTR_ISEQUALS_VAR_VAR 42
#define INSTR_ADDS_VAR_VAR 43
#define INSTR_SUBS_VAR_VAR 44
#define INSTR_MULS_VAR_VAR 45
#define INSTR_DIVS_VAR_VAR 46
/* }}} */
/* {{{ definition of the validation error types */
static const char *VALIDATE_OK = "ok";
#define VALIDATE_ERROR "error while validating "
#define VALIDATE_TODO "todo"
#define VALIDATE_SYNTHAX_ERROR "synthax error"
#define VALIDATE_NO_SUCH_INT "no such integer variable"
#define VALIDATE_NO_SUCH_VAR "no such variable"
#define VALIDATE_NO_SUCH_DEST_VAR "no such destination variable"
#define VALIDATE_NO_SUCH_SRC_VAR "no such src variable"
/* }}} */
/***********************************/
/* PROTOTYPE OF INTERNAL FUNCTIONS */
/***********************************/
/* {{{ */
static void gsl_instr_free(Instruction *_this);
static const char *gsl_instr_validate(Instruction *_this);
static void gsl_instr_display(Instruction *_this);
static InstructionFlow *iflow_new(void);
static void iflow_add_instr(InstructionFlow *_this, Instruction *instr);
static void iflow_clean(InstructionFlow *_this);
static void iflow_free(InstructionFlow *_this);
static void iflow_execute(FastInstructionFlow *_this, GoomSL *gsl);
/* }}} */
/************************************/
/* DEFINITION OF INTERNAL FUNCTIONS */
/************************************/
void iflow_free(InstructionFlow *_this)
{ /* {{{ */
goom_hash_free(_this->labels);
free(_this); /*TODO: finir cette fonction */
} /* }}} */
void iflow_clean(InstructionFlow *_this)
{ /* {{{ */
/* TODO: clean chaque instruction du flot */
_this->number = 0;
goom_hash_free(_this->labels);
_this->labels = goom_hash_new();
} /* }}} */
InstructionFlow *iflow_new(void)
{ /* {{{ */
InstructionFlow *_this = (InstructionFlow*)malloc(sizeof(InstructionFlow));
_this->number = 0;
_this->tabsize = 6;
_this->instr = (Instruction**)malloc(_this->tabsize * sizeof(Instruction*));
_this->labels = goom_hash_new();
return _this;
} /* }}} */
void iflow_add_instr(InstructionFlow *_this, Instruction *instr)
{ /* {{{ */
if (_this->number == _this->tabsize) {
_this->tabsize *= 2;
_this->instr = (Instruction**)realloc(_this->instr, _this->tabsize * sizeof(Instruction*));
}
_this->instr[_this->number] = instr;
instr->address = _this->number;
_this->number++;
} /* }}} */
void gsl_instr_set_namespace(Instruction *_this, GoomHash *ns)
{ /* {{{ */
if (_this->cur_param <= 0) {
fprintf(stderr, "ERROR: Line %d, No more params to instructions\n", _this->line_number);
exit(1);
}
_this->vnamespace[_this->cur_param-1] = ns;
} /* }}} */
void gsl_instr_add_param(Instruction *instr, char *param, int type)
{ /* {{{ */
int len;
if (instr==NULL)
return;
if (instr->cur_param==0)
return;
--instr->cur_param;
len = strlen(param);
instr->params[instr->cur_param] = (char*)malloc(len+1);
strcpy(instr->params[instr->cur_param], param);
instr->types[instr->cur_param] = type;
if (instr->cur_param == 0) {
const char *result = gsl_instr_validate(instr);
if (result != VALIDATE_OK) {
printf("ERROR: Line %d: ", instr->parent->num_lines + 1);
gsl_instr_display(instr);
printf("... %s\n", result);
instr->parent->compilationOK = 0;
exit(1);
}
#if USE_JITC_X86
iflow_add_instr(instr->parent->iflow, instr);
#else
if (instr->id != INSTR_NOP)
iflow_add_instr(instr->parent->iflow, instr);
else
gsl_instr_free(instr);
#endif
}
} /* }}} */
Instruction *gsl_instr_init(GoomSL *parent, const char *name, int id, int nb_param, int line_number)
{ /* {{{ */
Instruction *instr = (Instruction*)malloc(sizeof(Instruction));
instr->params = (char**)malloc(nb_param*sizeof(char*));
instr->vnamespace = (GoomHash**)malloc(nb_param*sizeof(GoomHash*));
instr->types = (int*)malloc(nb_param*sizeof(int));
instr->cur_param = instr->nb_param = nb_param;
instr->parent = parent;
instr->id = id;
instr->name = name;
instr->jump_label = NULL;
instr->line_number = line_number;
return instr;
} /* }}} */
void gsl_instr_free(Instruction *_this)
{ /* {{{ */
int i;
free(_this->types);
for (i=_this->cur_param; i<_this->nb_param; ++i)
free(_this->params[i]);
free(_this->params);
free(_this);
} /* }}} */
void gsl_instr_display(Instruction *_this)
{ /* {{{ */
int i=_this->nb_param-1;
printf("%s", _this->name);
while(i>=_this->cur_param) {
printf(" %s", _this->params[i]);
--i;
}
} /* }}} */
/****************************************/
/* VALIDATION OF INSTRUCTION PARAMETERS */
/****************************************/
static const char *validate_v_v(Instruction *_this)
{ /* {{{ */
HashValue *dest = goom_hash_get(_this->vnamespace[1], _this->params[1]);
HashValue *src = goom_hash_get(_this->vnamespace[0], _this->params[0]);
if (dest == NULL) {
return VALIDATE_NO_SUCH_DEST_VAR;
}
if (src == NULL) {
return VALIDATE_NO_SUCH_SRC_VAR;
}
_this->data.udest.var = dest->ptr;
_this->data.usrc.var = src->ptr;
return VALIDATE_OK;
} /* }}} */
static const char *validate_v_i(Instruction *_this)
{ /* {{{ */
HashValue *dest = goom_hash_get(_this->vnamespace[1], _this->params[1]);
_this->data.usrc.value_int = strtol(_this->params[0],NULL,0);
if (dest == NULL) {
return VALIDATE_NO_SUCH_INT;
}
_this->data.udest.var = dest->ptr;
return VALIDATE_OK;
} /* }}} */
static const char *validate_v_p(Instruction *_this)
{ /* {{{ */
HashValue *dest = goom_hash_get(_this->vnamespace[1], _this->params[1]);
_this->data.usrc.value_ptr = strtol(_this->params[0],NULL,0);
if (dest == NULL) {
return VALIDATE_NO_SUCH_INT;
}
_this->data.udest.var = dest->ptr;
return VALIDATE_OK;
} /* }}} */
static const char *validate_v_f(Instruction *_this)
{ /* {{{ */
HashValue *dest = goom_hash_get(_this->vnamespace[1], _this->params[1]);
_this->data.usrc.value_float = atof(_this->params[0]);
if (dest == NULL) {
return VALIDATE_NO_SUCH_VAR;
}
_this->data.udest.var = dest->ptr;
return VALIDATE_OK;
} /* }}} */
static const char *validate(Instruction *_this,
int vf_f_id, int vf_v_id,
int vi_i_id, int vi_v_id,
int vp_p_id, int vp_v_id,
int vs_v_id)
{ /* {{{ */
if ((_this->types[1] == TYPE_FVAR) && (_this->types[0] == TYPE_FLOAT)) {
_this->id = vf_f_id;
return validate_v_f(_this);
}
else if ((_this->types[1] == TYPE_FVAR) && (_this->types[0] == TYPE_FVAR)) {
_this->id = vf_v_id;
return validate_v_v(_this);
}
else if ((_this->types[1] == TYPE_IVAR) && (_this->types[0] == TYPE_INTEGER)) {
_this->id = vi_i_id;
return validate_v_i(_this);
}
else if ((_this->types[1] == TYPE_IVAR) && (_this->types[0] == TYPE_IVAR)) {
_this->id = vi_v_id;
return validate_v_v(_this);
}
else if ((_this->types[1] == TYPE_PVAR) && (_this->types[0] == TYPE_PTR)) {
if (vp_p_id == INSTR_NOP) return VALIDATE_ERROR;
_this->id = vp_p_id;
return validate_v_p(_this);
}
else if ((_this->types[1] == TYPE_PVAR) && (_this->types[0] == TYPE_PVAR)) {
_this->id = vp_v_id;
if (vp_v_id == INSTR_NOP) return VALIDATE_ERROR;
return validate_v_v(_this);
}
else if ((_this->types[1] < FIRST_RESERVED) && (_this->types[1] >= 0) && (_this->types[0] == _this->types[1])) {
_this->id = vs_v_id;
if (vs_v_id == INSTR_NOP) return "Impossible operation to perform between two structs";
return validate_v_v(_this);
}
return VALIDATE_ERROR;
} /* }}} */
const char *gsl_instr_validate(Instruction *_this)
{ /* {{{ */
if (_this->id != INSTR_EXT_CALL) {
int i = _this->nb_param;
while (i>0)
{
i--;
if (_this->types[i] == TYPE_VAR) {
int type = gsl_type_of_var(_this->vnamespace[i], _this->params[i]);
if (type == INSTR_INT)
_this->types[i] = TYPE_IVAR;
else if (type == INSTR_FLOAT)
_this->types[i] = TYPE_FVAR;
else if (type == INSTR_PTR)
_this->types[i] = TYPE_PVAR;
else if ((type >= 0) && (type < FIRST_RESERVED))
_this->types[i] = type;
else fprintf(stderr,"WARNING: Line %d, %s has no namespace\n", _this->line_number, _this->params[i]);
}
}
}
switch (_this->id) {
/* set */
case INSTR_SET:
return validate(_this,
INSTR_SETF_VAR_FLOAT, INSTR_SETF_VAR_VAR,
INSTR_SETI_VAR_INTEGER, INSTR_SETI_VAR_VAR,
INSTR_SETP_VAR_PTR, INSTR_SETP_VAR_VAR,
INSTR_SETS_VAR_VAR);
/* extcall */
case INSTR_EXT_CALL:
if (_this->types[0] == TYPE_VAR) {
HashValue *fval = goom_hash_get(_this->parent->functions, _this->params[0]);
if (fval) {
_this->data.udest.external_function = (struct _ExternalFunctionStruct*)fval->ptr;
return VALIDATE_OK;
}
}
return VALIDATE_ERROR;
/* call */
case INSTR_CALL:
if (_this->types[0] == TYPE_LABEL) {
_this->jump_label = _this->params[0];
return VALIDATE_OK;
}
return VALIDATE_ERROR;
/* ret */
case INSTR_RET:
return VALIDATE_OK;
/* jump */
case INSTR_JUMP:
if (_this->types[0] == TYPE_LABEL) {
_this->jump_label = _this->params[0];
return VALIDATE_OK;
}
return VALIDATE_ERROR;
/* jzero / jnzero */
case INSTR_JZERO:
case INSTR_JNZERO:
if (_this->types[0] == TYPE_LABEL) {
_this->jump_label = _this->params[0];
return VALIDATE_OK;
}
return VALIDATE_ERROR;
/* label */
case INSTR_LABEL:
if (_this->types[0] == TYPE_LABEL) {
_this->id = INSTR_NOP;
_this->nop_label = _this->params[0];
goom_hash_put_int(_this->parent->iflow->labels, _this->params[0], _this->parent->iflow->number);
return VALIDATE_OK;
}
return VALIDATE_ERROR;
/* isequal */
case INSTR_ISEQUAL:
return validate(_this,
INSTR_ISEQUALF_VAR_FLOAT, INSTR_ISEQUALF_VAR_VAR,
INSTR_ISEQUALI_VAR_INTEGER, INSTR_ISEQUALI_VAR_VAR,
INSTR_ISEQUALP_VAR_PTR, INSTR_ISEQUALP_VAR_VAR,
INSTR_ISEQUALS_VAR_VAR);
/* not */
case INSTR_NOT:
_this->id = INSTR_NOT_VAR;
return VALIDATE_OK;
/* islower */
case INSTR_ISLOWER:
return validate(_this,
INSTR_ISLOWERF_VAR_FLOAT, INSTR_ISLOWERF_VAR_VAR,
INSTR_ISLOWERI_VAR_INTEGER, INSTR_ISLOWERI_VAR_VAR,
INSTR_NOP, INSTR_NOP, INSTR_NOP);
/* add */
case INSTR_ADD:
return validate(_this,
INSTR_ADDF_VAR_FLOAT, INSTR_ADDF_VAR_VAR,
INSTR_ADDI_VAR_INTEGER, INSTR_ADDI_VAR_VAR,
INSTR_NOP, INSTR_NOP,
INSTR_ADDS_VAR_VAR);
/* mul */
case INSTR_MUL:
return validate(_this,
INSTR_MULF_VAR_FLOAT, INSTR_MULF_VAR_VAR,
INSTR_MULI_VAR_INTEGER, INSTR_MULI_VAR_VAR,
INSTR_NOP, INSTR_NOP,
INSTR_MULS_VAR_VAR);
/* sub */
case INSTR_SUB:
return validate(_this,
INSTR_SUBF_VAR_FLOAT, INSTR_SUBF_VAR_VAR,
INSTR_SUBI_VAR_INTEGER, INSTR_SUBI_VAR_VAR,
INSTR_NOP, INSTR_NOP,
INSTR_SUBS_VAR_VAR);
/* div */
case INSTR_DIV:
return validate(_this,
INSTR_DIVF_VAR_FLOAT, INSTR_DIVF_VAR_VAR,
INSTR_DIVI_VAR_INTEGER, INSTR_DIVI_VAR_VAR,
INSTR_NOP,INSTR_NOP,
INSTR_DIVS_VAR_VAR);
default:
return VALIDATE_TODO;
}
return VALIDATE_ERROR;
} /* }}} */
/*************/
/* EXECUTION */
/*************/
void iflow_execute(FastInstructionFlow *_this, GoomSL *gsl)
{ /* {{{ */
int flag = 0;
int ip = 0;
FastInstruction *instr = _this->instr;
int stack[0x10000];
int stack_pointer = 0;
stack[stack_pointer++] = -1;
/* Quelques Macro pour rendre le code plus lisible */
#define pSRC_VAR instr[ip].data.usrc.var
#define SRC_VAR_INT *instr[ip].data.usrc.var_int
#define SRC_VAR_FLOAT *instr[ip].data.usrc.var_float
#define SRC_VAR_PTR *instr[ip].data.usrc.var_ptr
#define pDEST_VAR instr[ip].data.udest.var
#define DEST_VAR_INT *instr[ip].data.udest.var_int
#define DEST_VAR_FLOAT *instr[ip].data.udest.var_float
#define DEST_VAR_PTR *instr[ip].data.udest.var_ptr
#define VALUE_INT instr[ip].data.usrc.value_int
#define VALUE_FLOAT instr[ip].data.usrc.value_float
#define VALUE_PTR instr[ip].data.usrc.value_ptr
#define JUMP_OFFSET instr[ip].data.udest.jump_offset
#define SRC_STRUCT_ID instr[ip].data.usrc.var_int[-1]
#define DEST_STRUCT_ID instr[ip].data.udest.var_int[-1]
#define SRC_STRUCT_IBLOCK(i) gsl->gsl_struct[SRC_STRUCT_ID]->iBlock[i]
#define SRC_STRUCT_FBLOCK(i) gsl->gsl_struct[SRC_STRUCT_ID]->fBlock[i]
#define DEST_STRUCT_IBLOCK(i) gsl->gsl_struct[DEST_STRUCT_ID]->iBlock[i]
#define DEST_STRUCT_FBLOCK(i) gsl->gsl_struct[DEST_STRUCT_ID]->fBlock[i]
#define DEST_STRUCT_IBLOCK_VAR(i,j) \
((int*)((char*)pDEST_VAR + gsl->gsl_struct[DEST_STRUCT_ID]->iBlock[i].data))[j]
#define DEST_STRUCT_FBLOCK_VAR(i,j) \
((float*)((char*)pDEST_VAR + gsl->gsl_struct[DEST_STRUCT_ID]->fBlock[i].data))[j]
#define SRC_STRUCT_IBLOCK_VAR(i,j) \
((int*)((char*)pSRC_VAR + gsl->gsl_struct[SRC_STRUCT_ID]->iBlock[i].data))[j]
#define SRC_STRUCT_FBLOCK_VAR(i,j) \
((float*)((char*)pSRC_VAR + gsl->gsl_struct[SRC_STRUCT_ID]->fBlock[i].data))[j]
#define DEST_STRUCT_SIZE gsl->gsl_struct[DEST_STRUCT_ID]->size
while (1)
{
int i;
#ifdef TRACE_SCRIPT
printf("execute "); gsl_instr_display(instr[ip].proto); printf("\n");
#endif
switch (instr[ip].id) {
/* SET.I */
case INSTR_SETI_VAR_INTEGER:
DEST_VAR_INT = VALUE_INT;
++ip; break;
case INSTR_SETI_VAR_VAR:
DEST_VAR_INT = SRC_VAR_INT;
++ip; break;
/* SET.F */
case INSTR_SETF_VAR_FLOAT:
DEST_VAR_FLOAT = VALUE_FLOAT;
++ip; break;
case INSTR_SETF_VAR_VAR:
DEST_VAR_FLOAT = SRC_VAR_FLOAT;
++ip; break;
/* SET.P */
case INSTR_SETP_VAR_VAR:
DEST_VAR_PTR = SRC_VAR_PTR;
++ip; break;
case INSTR_SETP_VAR_PTR:
DEST_VAR_PTR = VALUE_PTR;
++ip; break;
/* JUMP */
case INSTR_JUMP:
ip += JUMP_OFFSET; break;
/* JZERO */
case INSTR_JZERO:
ip += (flag ? 1 : JUMP_OFFSET); break;
case INSTR_NOP:
++ip; break;
/* ISEQUAL.P */
case INSTR_ISEQUALP_VAR_VAR:
flag = (DEST_VAR_PTR == SRC_VAR_PTR);
++ip; break;
case INSTR_ISEQUALP_VAR_PTR:
flag = (DEST_VAR_PTR == VALUE_PTR);
++ip; break;
/* ISEQUAL.I */
case INSTR_ISEQUALI_VAR_VAR:
flag = (DEST_VAR_INT == SRC_VAR_INT);
++ip; break;
case INSTR_ISEQUALI_VAR_INTEGER:
flag = (DEST_VAR_INT == VALUE_INT);
++ip; break;
/* ISEQUAL.F */
case INSTR_ISEQUALF_VAR_VAR:
flag = (DEST_VAR_FLOAT == SRC_VAR_FLOAT);
++ip; break;
case INSTR_ISEQUALF_VAR_FLOAT:
flag = (DEST_VAR_FLOAT == VALUE_FLOAT);
++ip; break;
/* ISLOWER.I */
case INSTR_ISLOWERI_VAR_VAR:
flag = (DEST_VAR_INT < SRC_VAR_INT);
++ip; break;
case INSTR_ISLOWERI_VAR_INTEGER:
flag = (DEST_VAR_INT < VALUE_INT);
++ip; break;
/* ISLOWER.F */
case INSTR_ISLOWERF_VAR_VAR:
flag = (DEST_VAR_FLOAT < SRC_VAR_FLOAT);
++ip; break;
case INSTR_ISLOWERF_VAR_FLOAT:
flag = (DEST_VAR_FLOAT < VALUE_FLOAT);
++ip; break;
/* ADD.I */
case INSTR_ADDI_VAR_VAR:
DEST_VAR_INT += SRC_VAR_INT;
++ip; break;
case INSTR_ADDI_VAR_INTEGER:
DEST_VAR_INT += VALUE_INT;
++ip; break;
/* ADD.F */
case INSTR_ADDF_VAR_VAR:
DEST_VAR_FLOAT += SRC_VAR_FLOAT;
++ip; break;
case INSTR_ADDF_VAR_FLOAT:
DEST_VAR_FLOAT += VALUE_FLOAT;
++ip; break;
/* MUL.I */
case INSTR_MULI_VAR_VAR:
DEST_VAR_INT *= SRC_VAR_INT;
++ip; break;
case INSTR_MULI_VAR_INTEGER:
DEST_VAR_INT *= VALUE_INT;
++ip; break;
/* MUL.F */
case INSTR_MULF_VAR_FLOAT:
DEST_VAR_FLOAT *= VALUE_FLOAT;
++ip; break;
case INSTR_MULF_VAR_VAR:
DEST_VAR_FLOAT *= SRC_VAR_FLOAT;
++ip; break;
/* DIV.I */
case INSTR_DIVI_VAR_VAR:
DEST_VAR_INT /= SRC_VAR_INT;
++ip; break;
case INSTR_DIVI_VAR_INTEGER:
DEST_VAR_INT /= VALUE_INT;
++ip; break;
/* DIV.F */
case INSTR_DIVF_VAR_FLOAT:
DEST_VAR_FLOAT /= VALUE_FLOAT;
++ip; break;
case INSTR_DIVF_VAR_VAR:
DEST_VAR_FLOAT /= SRC_VAR_FLOAT;
++ip; break;
/* SUB.I */
case INSTR_SUBI_VAR_VAR:
DEST_VAR_INT -= SRC_VAR_INT;
++ip; break;
case INSTR_SUBI_VAR_INTEGER:
DEST_VAR_INT -= VALUE_INT;
++ip; break;
/* SUB.F */
case INSTR_SUBF_VAR_FLOAT:
DEST_VAR_FLOAT -= VALUE_FLOAT;
++ip; break;
case INSTR_SUBF_VAR_VAR:
DEST_VAR_FLOAT -= SRC_VAR_FLOAT;
++ip; break;
/* CALL */
case INSTR_CALL:
stack[stack_pointer++] = ip + 1;
ip += JUMP_OFFSET; break;
/* RET */
case INSTR_RET:
ip = stack[--stack_pointer];
if (ip<0) return;
break;
/* EXT_CALL */
case INSTR_EXT_CALL:
instr[ip].data.udest.external_function->function(gsl, gsl->vars, instr[ip].data.udest.external_function->vars);
++ip; break;
/* NOT */
case INSTR_NOT_VAR:
flag = !flag;
++ip; break;
/* JNZERO */
case INSTR_JNZERO:
ip += (flag ? JUMP_OFFSET : 1); break;
case INSTR_SETS_VAR_VAR:
memcpy(pDEST_VAR, pSRC_VAR, DEST_STRUCT_SIZE);
++ip; break;
case INSTR_ISEQUALS_VAR_VAR:
break;
case INSTR_ADDS_VAR_VAR:
/* process integers */
i=0;
while (DEST_STRUCT_IBLOCK(i).size > 0) {
int j=DEST_STRUCT_IBLOCK(i).size;
while (j--) {
DEST_STRUCT_IBLOCK_VAR(i,j) += SRC_STRUCT_IBLOCK_VAR(i,j);
}
++i;
}
/* process floats */
i=0;
while (DEST_STRUCT_FBLOCK(i).size > 0) {
int j=DEST_STRUCT_FBLOCK(i).size;
while (j--) {
DEST_STRUCT_FBLOCK_VAR(i,j) += SRC_STRUCT_FBLOCK_VAR(i,j);
}
++i;
}
++ip; break;
case INSTR_SUBS_VAR_VAR:
/* process integers */
i=0;
while (DEST_STRUCT_IBLOCK(i).size > 0) {
int j=DEST_STRUCT_IBLOCK(i).size;
while (j--) {
DEST_STRUCT_IBLOCK_VAR(i,j) -= SRC_STRUCT_IBLOCK_VAR(i,j);
}
++i;
}
/* process floats */
i=0;
while (DEST_STRUCT_FBLOCK(i).size > 0) {
int j=DEST_STRUCT_FBLOCK(i).size;
while (j--) {
DEST_STRUCT_FBLOCK_VAR(i,j) -= SRC_STRUCT_FBLOCK_VAR(i,j);
}
++i;
}
++ip; break;
case INSTR_MULS_VAR_VAR:
/* process integers */
i=0;
while (DEST_STRUCT_IBLOCK(i).size > 0) {
int j=DEST_STRUCT_IBLOCK(i).size;
while (j--) {
DEST_STRUCT_IBLOCK_VAR(i,j) *= SRC_STRUCT_IBLOCK_VAR(i,j);
}
++i;
}
/* process floats */
i=0;
while (DEST_STRUCT_FBLOCK(i).size > 0) {
int j=DEST_STRUCT_FBLOCK(i).size;
while (j--) {
DEST_STRUCT_FBLOCK_VAR(i,j) *= SRC_STRUCT_FBLOCK_VAR(i,j);
}
++i;
}
++ip; break;
case INSTR_DIVS_VAR_VAR:
/* process integers */
i=0;
while (DEST_STRUCT_IBLOCK(i).size > 0) {
int j=DEST_STRUCT_IBLOCK(i).size;
while (j--) {
DEST_STRUCT_IBLOCK_VAR(i,j) /= SRC_STRUCT_IBLOCK_VAR(i,j);
}
++i;
}
/* process floats */
i=0;
while (DEST_STRUCT_FBLOCK(i).size > 0) {
int j=DEST_STRUCT_FBLOCK(i).size;
while (j--) {
DEST_STRUCT_FBLOCK_VAR(i,j) /= SRC_STRUCT_FBLOCK_VAR(i,j);
}
++i;
}
++ip; break;
default:
printf("NOT IMPLEMENTED : %d\n", instr[ip].id);
++ip;
exit(1);
}
}
} /* }}} */
int gsl_malloc(GoomSL *_this, int size)
{ /* {{{ */
if (_this->nbPtr >= _this->ptrArraySize) {
_this->ptrArraySize *= 2;
_this->ptrArray = (void**)realloc(_this->ptrArray, sizeof(void*) * _this->ptrArraySize);
}
_this->ptrArray[_this->nbPtr] = malloc(size);
return _this->nbPtr++;
} /* }}} */
void *gsl_get_ptr(GoomSL *_this, int id)
{ /* {{{ */
if ((id>=0)&&(id<_this->nbPtr))
return _this->ptrArray[id];
fprintf(stderr,"INVALID GET PTR 0x%08x\n", id);
return NULL;
} /* }}} */
void gsl_free_ptr(GoomSL *_this, int id)
{ /* {{{ */
if ((id>=0)&&(id<_this->nbPtr)) {
free(_this->ptrArray[id]);
_this->ptrArray[id] = 0;
}
} /* }}} */
void gsl_enternamespace(const char *name)
{ /* {{{ */
HashValue *val = goom_hash_get(currentGoomSL->functions, name);
if (val) {
ExternalFunctionStruct *function = (ExternalFunctionStruct*)val->ptr;
currentGoomSL->currentNS++;
currentGoomSL->namespaces[currentGoomSL->currentNS] = function->vars;
}
else {
fprintf(stderr, "ERROR: Line %d, Could not find namespace: %s\n", currentGoomSL->num_lines, name);
exit(1);
}
} /* }}} */
void gsl_reenternamespace(GoomHash *nsinfo) {
currentGoomSL->currentNS++;
currentGoomSL->namespaces[currentGoomSL->currentNS] = nsinfo;
}
GoomHash *gsl_leavenamespace(void)
{ /* {{{ */
currentGoomSL->currentNS--;
return currentGoomSL->namespaces[currentGoomSL->currentNS+1];
} /* }}} */
GoomHash *gsl_find_namespace(const char *name)
{ /* {{{ */
int i;
for (i=currentGoomSL->currentNS;i>=0;--i) {
if (goom_hash_get(currentGoomSL->namespaces[i], name))
return currentGoomSL->namespaces[i];
}
return NULL;
} /* }}} */
void gsl_declare_task(const char *name)
{ /* {{{ */
if (goom_hash_get(currentGoomSL->functions, name)) {
return;
}
else {
ExternalFunctionStruct *gef = (ExternalFunctionStruct*)malloc(sizeof(ExternalFunctionStruct));
gef->function = 0;
gef->vars = goom_hash_new();
gef->is_extern = 0;
goom_hash_put_ptr(currentGoomSL->functions, name, (void*)gef);
}
} /* }}} */
void gsl_declare_external_task(const char *name)
{ /* {{{ */
if (goom_hash_get(currentGoomSL->functions, name)) {
fprintf(stderr, "ERROR: Line %d, Duplicate declaration of %s\n", currentGoomSL->num_lines, name);
return;
}
else {
ExternalFunctionStruct *gef = (ExternalFunctionStruct*)malloc(sizeof(ExternalFunctionStruct));
gef->function = 0;
gef->vars = goom_hash_new();
gef->is_extern = 1;
goom_hash_put_ptr(currentGoomSL->functions, name, (void*)gef);
}
} /* }}} */
static void reset_scanner(GoomSL *gss)
{ /* {{{ */
gss->num_lines = 0;
gss->instr = NULL;
iflow_clean(gss->iflow);
/* reset variables */
goom_hash_free(gss->vars);
gss->vars = goom_hash_new();
gss->currentNS = 0;
gss->namespaces[0] = gss->vars;
goom_hash_free(gss->structIDS);
gss->structIDS = goom_hash_new();
while (gss->nbStructID > 0) {
int i;
gss->nbStructID--;
for(i=0;i<gss->gsl_struct[gss->nbStructID]->nbFields;++i)
free(gss->gsl_struct[gss->nbStructID]->fields[i]);
free(gss->gsl_struct[gss->nbStructID]);
}
gss->compilationOK = 1;
goom_heap_delete(gss->data_heap);
gss->data_heap = goom_heap_new();
} /* }}} */
static void calculate_labels(InstructionFlow *iflow)
{ /* {{{ */
int i = 0;
while (i < iflow->number) {
Instruction *instr = iflow->instr[i];
if (instr->jump_label) {
HashValue *label = goom_hash_get(iflow->labels,instr->jump_label);
if (label) {
instr->data.udest.jump_offset = -instr->address + label->i;
}
else {
fprintf(stderr, "ERROR: Line %d, Could not find label %s\n", instr->line_number, instr->jump_label);
instr->id = INSTR_NOP;
instr->nop_label = 0;
exit(1);
}
}
++i;
}
} /* }}} */
static int powerOfTwo(int i)
{
int b;
for (b=0;b<31;b++)
if (i == (1<<b))
return b;
return 0;
}
/* Cree un flow d'instruction optimise */
static void gsl_create_fast_iflow(void)
{ /* {{{ */
int number = currentGoomSL->iflow->number;
int i;
#ifdef USE_JITC_X86
/* pour compatibilite avec les MACROS servant a execution */
int ip = 0;
GoomSL *gsl = currentGoomSL;
JitcX86Env *jitc;
if (currentGoomSL->jitc != NULL)
jitc_x86_delete(currentGoomSL->jitc);
jitc = currentGoomSL->jitc = jitc_x86_env_new(0xffff);
currentGoomSL->jitc_func = jitc_prepare_func(jitc);
#if 0
#define SRC_STRUCT_ID instr[ip].data.usrc.var_int[-1]
#define DEST_STRUCT_ID instr[ip].data.udest.var_int[-1]
#define SRC_STRUCT_IBLOCK(i) gsl->gsl_struct[SRC_STRUCT_ID]->iBlock[i]
#define SRC_STRUCT_FBLOCK(i) gsl->gsl_struct[SRC_STRUCT_ID]->fBlock[i]
#define DEST_STRUCT_IBLOCK(i) gsl->gsl_struct[DEST_STRUCT_ID]->iBlock[i]
#define DEST_STRUCT_FBLOCK(i) gsl->gsl_struct[DEST_STRUCT_ID]->fBlock[i]
#define DEST_STRUCT_IBLOCK_VAR(i,j) \
((int*)((char*)pDEST_VAR + gsl->gsl_struct[DEST_STRUCT_ID]->iBlock[i].data))[j]
#define DEST_STRUCT_FBLOCK_VAR(i,j) \
((float*)((char*)pDEST_VAR + gsl->gsl_struct[DEST_STRUCT_ID]->fBlock[i].data))[j]
#define SRC_STRUCT_IBLOCK_VAR(i,j) \
((int*)((char*)pSRC_VAR + gsl->gsl_struct[SRC_STRUCT_ID]->iBlock[i].data))[j]
#define SRC_STRUCT_FBLOCK_VAR(i,j) \
((float*)((char*)pSRC_VAR + gsl->gsl_struct[SRC_STRUCT_ID]->fBlock[i].data))[j]
#define DEST_STRUCT_SIZE gsl->gsl_struct[DEST_STRUCT_ID]->size
#endif
JITC_JUMP_LABEL(jitc, "__very_end__");
JITC_ADD_LABEL (jitc, "__very_start__");
for (i=0;i<number;++i) {
Instruction *instr = currentGoomSL->iflow->instr[i];
switch (instr->id) {
case INSTR_SETI_VAR_INTEGER :
jitc_add(jitc, "mov [$d], $d", instr->data.udest.var_int, instr->data.usrc.value_int);
break;
case INSTR_SETI_VAR_VAR :
jitc_add(jitc, "mov eax, [$d]", instr->data.usrc.var_int);
jitc_add(jitc, "mov [$d], eax", instr->data.udest.var_int);
break;
/* SET.F */
case INSTR_SETF_VAR_FLOAT :
jitc_add(jitc, "mov [$d], $d", instr->data.udest.var_float, *(int*)(&instr->data.usrc.value_float));
break;
case INSTR_SETF_VAR_VAR :
jitc_add(jitc, "mov eax, [$d]", instr->data.usrc.var_float);
jitc_add(jitc, "mov [$d], eax", instr->data.udest.var_float);
break;
case INSTR_NOP :
if (instr->nop_label != 0)
JITC_ADD_LABEL(jitc, instr->nop_label);
break;
case INSTR_JUMP :
JITC_JUMP_LABEL(jitc,instr->jump_label);
break;
case INSTR_SETP_VAR_PTR :
jitc_add(jitc, "mov [$d], $d", instr->data.udest.var_ptr, instr->data.usrc.value_ptr);
break;
case INSTR_SETP_VAR_VAR :
jitc_add(jitc, "mov eax, [$d]", instr->data.usrc.var_ptr);
jitc_add(jitc, "mov [$d], eax", instr->data.udest.var_ptr);
break;
case INSTR_SUBI_VAR_INTEGER :
jitc_add(jitc, "add [$d], $d", instr->data.udest.var_int, -instr->data.usrc.value_int);
break;
case INSTR_SUBI_VAR_VAR :
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_int);
jitc_add(jitc, "sub eax, [$d]", instr->data.usrc.var_int);
jitc_add(jitc, "mov [$d], eax", instr->data.udest.var_int);
break;
case INSTR_SUBF_VAR_FLOAT :
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_SUBF_VAR_VAR :
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_ISLOWERF_VAR_VAR:
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_ISLOWERF_VAR_FLOAT:
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_ISLOWERI_VAR_VAR:
jitc_add(jitc,"mov edx, [$d]", instr->data.udest.var_int);
jitc_add(jitc,"sub edx, [$d]", instr->data.usrc.var_int);
jitc_add(jitc,"shr edx, $d", 31);
break;
case INSTR_ISLOWERI_VAR_INTEGER:
jitc_add(jitc,"mov edx, [$d]", instr->data.udest.var_int);
jitc_add(jitc,"sub edx, $d", instr->data.usrc.value_int);
jitc_add(jitc,"shr edx, $d", 31);
break;
case INSTR_ADDI_VAR_INTEGER:
jitc_add(jitc, "add [$d], $d", instr->data.udest.var_int, instr->data.usrc.value_int);
break;
case INSTR_ADDI_VAR_VAR:
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_int);
jitc_add(jitc, "add eax, [$d]", instr->data.usrc.var_int);
jitc_add(jitc, "mov [$d], eax", instr->data.udest.var_int);
break;
case INSTR_ADDF_VAR_FLOAT:
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_ADDF_VAR_VAR:
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_MULI_VAR_INTEGER:
if (instr->data.usrc.value_int != 1)
{
int po2 = powerOfTwo(instr->data.usrc.value_int);
if (po2) {
/* performs (V / 2^n) by doing V >> n */
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_int);
jitc_add(jitc, "sal eax, $d", po2);
jitc_add(jitc, "mov [$d], eax", instr->data.udest.var_int);
}
else {
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_int);
jitc_add(jitc, "imul eax, $d", instr->data.usrc.value_int);
jitc_add(jitc, "mov [$d], eax", instr->data.udest.var_int);
}
}
break;
case INSTR_MULI_VAR_VAR:
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_int);
jitc_add(jitc, "imul eax, [$d]", instr->data.usrc.var_int);
jitc_add(jitc, "mov [$d], eax", instr->data.udest.var_int);
break;
case INSTR_MULF_VAR_FLOAT:
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_MULF_VAR_VAR:
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_DIVI_VAR_INTEGER:
if ((instr->data.usrc.value_int != 1) && (instr->data.usrc.value_int != 0))
{
int po2 = powerOfTwo(instr->data.usrc.value_int);
if (po2) {
/* performs (V / 2^n) by doing V >> n */
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_int);
jitc_add(jitc, "sar eax, $d", po2);
jitc_add(jitc, "mov [$d], eax", instr->data.udest.var_int);
}
else {
/* performs (V/n) by doing (V*(32^2/n)) */
long coef;
double dcoef = (double)4294967296.0 / (double)instr->data.usrc.value_int;
if (dcoef < 0.0) dcoef = -dcoef;
coef = (long)floor(dcoef);
dcoef -= floor(dcoef);
if (dcoef < 0.5) coef += 1;
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_int);
jitc_add(jitc, "mov edx, $d", coef);
jitc_add(jitc, "imul edx");
if (instr->data.usrc.value_int < 0)
jitc_add(jitc, "neg edx");
jitc_add(jitc, "mov [$d], edx", instr->data.udest.var_int);
}
}
break;
case INSTR_DIVI_VAR_VAR :
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_int);
jitc_add(jitc, "cdq"); /* sign extend eax into edx */
jitc_add(jitc, "idiv [$d]", instr->data.usrc.var_int);
jitc_add(jitc, "mov [$d], eax", instr->data.udest.var_int);
break;
case INSTR_DIVF_VAR_FLOAT:
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_DIVF_VAR_VAR:
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_JZERO:
jitc_add(jitc, "cmp edx, $d", 0);
jitc_add(jitc, "je $s", instr->jump_label);
break;
case INSTR_ISEQUALP_VAR_VAR :
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_ptr);
jitc_add(jitc, "mov edx, $d", 0);
jitc_add(jitc, "cmp eax, [$d]", instr->data.usrc.var_ptr);
jitc_add(jitc, "jne $d", 1);
jitc_add(jitc, "inc edx");
break;
case INSTR_ISEQUALP_VAR_PTR :
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_ptr);
jitc_add(jitc, "mov edx, $d", 0);
jitc_add(jitc, "cmp eax, $d", instr->data.usrc.value_ptr);
jitc_add(jitc, "jne $d", 1);
jitc_add(jitc, "inc edx");
break;
case INSTR_ISEQUALI_VAR_VAR :
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_int);
jitc_add(jitc, "mov edx, $d", 0);
jitc_add(jitc, "cmp eax, [$d]", instr->data.usrc.var_int);
jitc_add(jitc, "jne $d", 1);
jitc_add(jitc, "inc edx");
break;
case INSTR_ISEQUALI_VAR_INTEGER :
jitc_add(jitc, "mov eax, [$d]", instr->data.udest.var_int);
jitc_add(jitc, "mov edx, $d", 0);
jitc_add(jitc, "cmp eax, $d", instr->data.usrc.value_int);
jitc_add(jitc, "jne $d", 1);
jitc_add(jitc, "inc edx");
break;
case INSTR_ISEQUALF_VAR_VAR :
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_ISEQUALF_VAR_FLOAT :
printf("NOT IMPLEMENTED : %d\n", instr->id);
break;
case INSTR_CALL:
jitc_add(jitc, "call $s", instr->jump_label);
break;
case INSTR_RET:
jitc_add(jitc, "ret");
break;
case INSTR_EXT_CALL:
jitc_add(jitc, "mov eax, [$d]", &(instr->data.udest.external_function->vars));
jitc_add(jitc, "push eax");
jitc_add(jitc, "mov edx, [$d]", &(currentGoomSL->vars));
jitc_add(jitc, "push edx");
jitc_add(jitc, "mov eax, [$d]", &(currentGoomSL));
jitc_add(jitc, "push eax");
jitc_add(jitc, "mov eax, [$d]", &(instr->data.udest.external_function));
jitc_add(jitc, "mov eax, [eax]");
jitc_add(jitc, "call [eax]");
jitc_add(jitc, "add esp, $d", 12);
break;
case INSTR_NOT_VAR:
jitc_add(jitc, "mov eax, edx");
jitc_add(jitc, "mov edx, $d", 1);
jitc_add(jitc, "sub edx, eax");
break;
case INSTR_JNZERO:
jitc_add(jitc, "cmp edx, $d", 0);
jitc_add(jitc, "jne $s", instr->jump_label);
break;
case INSTR_SETS_VAR_VAR:
{
int loop = DEST_STRUCT_SIZE / sizeof(int);
int dst = (int)pDEST_VAR;
int src = (int)pSRC_VAR;
while (loop--) {
jitc_add(jitc,"mov eax, [$d]", src);
jitc_add(jitc,"mov [$d], eax", dst);
src += 4;
dst += 4;
}
}
break;
case INSTR_ISEQUALS_VAR_VAR:
break;
case INSTR_ADDS_VAR_VAR:
{
/* process integers */
int i=0;
while (DEST_STRUCT_IBLOCK(i).size > 0) {
int j=DEST_STRUCT_IBLOCK(i).size;
while (j--) { /* TODO interlace 2 */
jitc_add(jitc, "mov eax, [$d]", &DEST_STRUCT_IBLOCK_VAR(i,j));
jitc_add(jitc, "add eax, [$d]", &SRC_STRUCT_IBLOCK_VAR(i,j));
jitc_add(jitc, "mov [$d], eax", &DEST_STRUCT_IBLOCK_VAR(i,j));
}
++i;
}
/* process floats */
i=0;
while (DEST_STRUCT_FBLOCK(i).size > 0) {
int j=DEST_STRUCT_FBLOCK(i).size;
while (j--) {
/* DEST_STRUCT_FBLOCK_VAR(i,j) += SRC_STRUCT_FBLOCK_VAR(i,j); */
/* TODO */
}
++i;
}
break;
}
case INSTR_SUBS_VAR_VAR:
{
/* process integers */
int i=0;
while (DEST_STRUCT_IBLOCK(i).size > 0) {
int j=DEST_STRUCT_IBLOCK(i).size;
while (j--) {
jitc_add(jitc, "mov eax, [$d]", &DEST_STRUCT_IBLOCK_VAR(i,j));
jitc_add(jitc, "sub eax, [$d]", &SRC_STRUCT_IBLOCK_VAR(i,j));
jitc_add(jitc, "mov [$d], eax", &DEST_STRUCT_IBLOCK_VAR(i,j));
}
++i;
}
break;
}
case INSTR_MULS_VAR_VAR:
{
/* process integers */
int i=0;
while (DEST_STRUCT_IBLOCK(i).size > 0) {
int j=DEST_STRUCT_IBLOCK(i).size;
while (j--) {
jitc_add(jitc, "mov eax, [$d]", &DEST_STRUCT_IBLOCK_VAR(i,j));
jitc_add(jitc, "imul eax, [$d]", &SRC_STRUCT_IBLOCK_VAR(i,j));
jitc_add(jitc, "mov [$d], eax", &DEST_STRUCT_IBLOCK_VAR(i,j));
}
++i;
}
break;
}
case INSTR_DIVS_VAR_VAR:
{
/* process integers */
int i=0;
while (DEST_STRUCT_IBLOCK(i).size > 0) {
int j=DEST_STRUCT_IBLOCK(i).size;
while (j--) {
jitc_add(jitc, "mov eax, [$d]", &DEST_STRUCT_IBLOCK_VAR(i,j));
jitc_add(jitc, "cdq");
jitc_add(jitc, "idiv [$d]", &SRC_STRUCT_IBLOCK_VAR(i,j));
jitc_add(jitc, "mov [$d], eax", &DEST_STRUCT_IBLOCK_VAR(i,j));
}
++i;
}
break;
}
}
}
JITC_ADD_LABEL (jitc, "__very_end__");
jitc_add(jitc, "call $s", "__very_start__");
jitc_add(jitc, "mov eax, $d", 0);
jitc_validate_func(jitc);
#else
InstructionFlow *iflow = currentGoomSL->iflow;
FastInstructionFlow *fastiflow = (FastInstructionFlow*)malloc(sizeof(FastInstructionFlow));
fastiflow->mallocedInstr = calloc(number*16, sizeof(FastInstruction));
/* fastiflow->instr = (FastInstruction*)(((int)fastiflow->mallocedInstr) + 16 - (((int)fastiflow->mallocedInstr)%16)); */
fastiflow->instr = (FastInstruction*)fastiflow->mallocedInstr;
fastiflow->number = number;
for(i=0;i<number;++i) {
fastiflow->instr[i].id = iflow->instr[i]->id;
fastiflow->instr[i].data = iflow->instr[i]->data;
fastiflow->instr[i].proto = iflow->instr[i];
}
currentGoomSL->fastiflow = fastiflow;
#endif
} /* }}} */
void yy_scan_string(const char *str);
void yyparse(void);
GoomHash *gsl_globals(GoomSL *_this)
{
return _this->vars;
}
/**
* Some native external functions
*/
static void ext_charAt(GoomSL *gsl, GoomHash *global, GoomHash *local)
{
char *string = GSL_LOCAL_PTR(gsl, local, "value");
int index = GSL_LOCAL_INT(gsl, local, "index");
GSL_GLOBAL_INT(gsl, "charAt") = 0;
if (string == NULL) {
return;
}
if (index < strlen(string))
GSL_GLOBAL_INT(gsl, "charAt") = string[index];
}
static void ext_i2f(GoomSL *gsl, GoomHash *global, GoomHash *local)
{
int i = GSL_LOCAL_INT(gsl, local, "value");
GSL_GLOBAL_FLOAT(gsl, "i2f") = i;
}
static void ext_f2i(GoomSL *gsl, GoomHash *global, GoomHash *local)
{
float f = GSL_LOCAL_FLOAT(gsl, local, "value");
GSL_GLOBAL_INT(gsl, "f2i") = f;
}
/**
*
*/
void gsl_compile(GoomSL *_currentGoomSL, const char *script)
{ /* {{{ */
char *script_and_externals;
static const char *sBinds =
"external <charAt: string value, int index> : int\n"
"external <f2i: float value> : int\n"
"external <i2f: int value> : float\n";
#ifdef VERBOSE
printf("\n=== Starting Compilation ===\n");
#endif
script_and_externals = malloc(strlen(script) + strlen(sBinds) + 2);
strcpy(script_and_externals, sBinds);
strcat(script_and_externals, script);
/* 0- reset */
currentGoomSL = _currentGoomSL;
reset_scanner(currentGoomSL);
/* 1- create the syntaxic tree */
yy_scan_string(script_and_externals);
yyparse();
/* 2- generate code */
gsl_commit_compilation();
/* 3- resolve symbols */
calculate_labels(currentGoomSL->iflow);
/* 4- optimize code */
gsl_create_fast_iflow();
/* 5- bind a few internal functions */
gsl_bind_function(currentGoomSL, "charAt", ext_charAt);
gsl_bind_function(currentGoomSL, "f2i", ext_f2i);
gsl_bind_function(currentGoomSL, "i2f", ext_i2f);
free(script_and_externals);
#ifdef VERBOSE
printf("=== Compilation done. # of lines: %d. # of instr: %d ===\n", currentGoomSL->num_lines, currentGoomSL->iflow->number);
#endif
} /* }}} */
void gsl_execute(GoomSL *scanner)
{ /* {{{ */
if (scanner->compilationOK) {
#if USE_JITC_X86
scanner->jitc_func();
#else
iflow_execute(scanner->fastiflow, scanner);
#endif
}
} /* }}} */
GoomSL *gsl_new(void)
{ /* {{{ */
GoomSL *gss = (GoomSL*)malloc(sizeof(GoomSL));
gss->iflow = iflow_new();
gss->vars = goom_hash_new();
gss->functions = goom_hash_new();
gss->nbStructID = 0;
gss->structIDS = goom_hash_new();
gss->gsl_struct_size = 32;
gss->gsl_struct = (GSL_Struct**)malloc(gss->gsl_struct_size * sizeof(GSL_Struct*));
gss->currentNS = 0;
gss->namespaces[0] = gss->vars;
gss->data_heap = goom_heap_new();
reset_scanner(gss);
gss->compilationOK = 0;
gss->nbPtr=0;
gss->ptrArraySize=256;
gss->ptrArray = (void**)malloc(gss->ptrArraySize * sizeof(void*));
#ifdef USE_JITC_X86
gss->jitc = NULL;
#endif
return gss;
} /* }}} */
void gsl_bind_function(GoomSL *gss, const char *fname, GoomSL_ExternalFunction func)
{ /* {{{ */
HashValue *val = goom_hash_get(gss->functions, fname);
if (val) {
ExternalFunctionStruct *gef = (ExternalFunctionStruct*)val->ptr;
gef->function = func;
}
else fprintf(stderr, "Unable to bind function %s\n", fname);
} /* }}} */
int gsl_is_compiled(GoomSL *gss)
{ /* {{{ */
return gss->compilationOK;
} /* }}} */
void gsl_free(GoomSL *gss)
{ /* {{{ */
iflow_free(gss->iflow);
free(gss->vars);
free(gss->functions);
free(gss);
} /* }}} */
static int gsl_nb_import;
static char gsl_already_imported[256][256];
char *gsl_init_buffer(const char *fname)
{
char *fbuffer;
fbuffer = (char*)malloc(512);
fbuffer[0]=0;
gsl_nb_import = 0;
if (fname)
gsl_append_file_to_buffer(fname,&fbuffer);
return fbuffer;
}
static char *gsl_read_file(const char *fname)
{
FILE *f;
char *buffer;
int fsize;
f = fopen(fname,"rt");
if (!f) {
fprintf(stderr, "ERROR: Could not load file %s\n", fname);
exit(1);
}
fseek(f,0,SEEK_END);
fsize = ftell(f);
rewind(f);
buffer = (char*)malloc(fsize+512);
fread(buffer,1,fsize,f);
fclose(f);
buffer[fsize]=0;
return buffer;
}
void gsl_append_file_to_buffer(const char *fname, char **buffer)
{
char *fbuffer;
int size,fsize,i=0;
char reset_msg[256];
/* look if the file have not been already imported */
for (i=0;i<gsl_nb_import;++i) {
if (strcmp(gsl_already_imported[i], fname) == 0)
return;
}
/* add fname to the already imported files. */
strcpy(gsl_already_imported[gsl_nb_import++], fname);
/* load the file */
fbuffer = gsl_read_file(fname);
fsize = strlen(fbuffer);
/* look for #import */
while (fbuffer[i]) {
if ((fbuffer[i]=='#') && (fbuffer[i+1]=='i')) {
char impName[256];
int j;
while (fbuffer[i] && (fbuffer[i]!=' '))
i++;
i++;
j=0;
while (fbuffer[i] && (fbuffer[i]!='\n'))
impName[j++] = fbuffer[i++];
impName[j++] = 0;
gsl_append_file_to_buffer(impName, buffer);
}
i++;
}
sprintf(reset_msg, "\n#FILE %s#\n#RST_LINE#\n", fname);
strcat(*buffer, reset_msg);
size=strlen(*buffer);
*buffer = (char*)realloc(*buffer, size+fsize+256);
strcat((*buffer)+size, fbuffer);
free(fbuffer);
}