mirror of
https://github.com/ccxvii/mujs.git
synced 2026-02-06 01:41:37 +08:00
Begin generating byte code.
This commit is contained in:
10
js.h
10
js.h
@@ -10,15 +10,21 @@
|
||||
#include <math.h>
|
||||
|
||||
typedef struct js_State js_State;
|
||||
|
||||
typedef struct js_StringNode js_StringNode;
|
||||
typedef struct js_Ast js_Ast;
|
||||
|
||||
typedef enum js_ValueType js_ValueType;
|
||||
typedef struct js_Value js_Value;
|
||||
typedef struct js_RegExp js_RegExp;
|
||||
typedef struct js_Object js_Object;
|
||||
typedef struct js_Function js_Function;
|
||||
typedef int (*js_CFunction)(js_State *J);
|
||||
|
||||
#define JS_REGEXP_G 1
|
||||
#define JS_REGEXP_I 2
|
||||
#define JS_REGEXP_M 4
|
||||
|
||||
typedef int (*js_CFunction)(js_State *J);
|
||||
|
||||
js_State *js_newstate(void);
|
||||
void js_close(js_State *J);
|
||||
|
||||
|
||||
450
jscompile.c
Normal file
450
jscompile.c
Normal file
@@ -0,0 +1,450 @@
|
||||
#include "js.h"
|
||||
#include "jsparse.h"
|
||||
#include "jscompile.h"
|
||||
#include "jsrun.h"
|
||||
#include "jsstate.h"
|
||||
|
||||
#define cexp js_cexp /* collision with math.h */
|
||||
|
||||
#define JF js_State *J, js_Function *F
|
||||
|
||||
static void cexp(JF, js_Ast *exp);
|
||||
static void cstmlist(JF, js_Ast *list);
|
||||
|
||||
static int consteq(js_Value a, js_Value b)
|
||||
{
|
||||
if (a.type != b.type)
|
||||
return 0;
|
||||
if (a.type == JS_TNUMBER)
|
||||
return a.u.number == b.u.number;
|
||||
else
|
||||
return a.u.p == b.u.p;
|
||||
}
|
||||
|
||||
static int addconst(JF, js_Value v)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < F->klen; i++) {
|
||||
if (consteq(F->klist[i], v)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
if (F->klen >= F->kcap) {
|
||||
F->kcap *= 2;
|
||||
F->klist = realloc(F->klist, F->kcap * sizeof(js_Value));
|
||||
}
|
||||
|
||||
F->klist[F->klen] = v;
|
||||
return F->klen++;
|
||||
}
|
||||
|
||||
static void emit(JF, int value)
|
||||
{
|
||||
if (F->len >= F->cap) {
|
||||
F->cap *= 2;
|
||||
F->code = realloc(F->code, F->cap);
|
||||
}
|
||||
|
||||
F->code[F->len++] = value;
|
||||
}
|
||||
|
||||
static void emitnumber(JF, int opcode, double n)
|
||||
{
|
||||
js_Value v;
|
||||
v.type = JS_TNUMBER;
|
||||
v.u.number = n;
|
||||
emit(J, F, opcode);
|
||||
emit(J, F, addconst(J, F, v));
|
||||
}
|
||||
|
||||
static void emitstring(JF, int opcode, const char *s)
|
||||
{
|
||||
js_Value v;
|
||||
v.type = JS_TSTRING;
|
||||
v.u.string = s;
|
||||
emit(J, F, opcode);
|
||||
emit(J, F, addconst(J, F, v));
|
||||
}
|
||||
|
||||
static void unary(JF, js_Ast *exp, int opcode)
|
||||
{
|
||||
cexp(J, F, exp->a);
|
||||
emit(J, F, opcode);
|
||||
}
|
||||
|
||||
static void binary(JF, js_Ast *exp, int opcode)
|
||||
{
|
||||
cexp(J, F, exp->a);
|
||||
cexp(J, F, exp->b);
|
||||
emit(J, F, opcode);
|
||||
}
|
||||
|
||||
static void carray(JF, js_Ast *list)
|
||||
{
|
||||
while (list) {
|
||||
cexp(J, F, list->a);
|
||||
emit(J, F, OP_ARRAYPUT);
|
||||
list = list->b;
|
||||
}
|
||||
}
|
||||
|
||||
static void cobject(JF, js_Ast *list)
|
||||
{
|
||||
while (list) {
|
||||
js_Ast *kv = list->a;
|
||||
if (kv->type == EXP_PROP_VAL) {
|
||||
js_Ast *prop = kv->a;
|
||||
cexp(J, F, kv->b);
|
||||
if (prop->type == AST_IDENTIFIER || prop->type == AST_STRING)
|
||||
emitstring(J, F, OP_OBJECTPUT, prop->string);
|
||||
else if (prop->type == AST_NUMBER)
|
||||
emitnumber(J, F, OP_OBJECTPUT, prop->number);
|
||||
else
|
||||
jsC_error(J, list, "illegal property name in object initializer");
|
||||
}
|
||||
// TODO: set, get
|
||||
list = list->b;
|
||||
}
|
||||
}
|
||||
|
||||
static int cargs(JF, js_Ast *list)
|
||||
{
|
||||
int n = 0;
|
||||
while (list) {
|
||||
cexp(J, F, list->a);
|
||||
list = list->b;
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void clval(JF, js_Ast *exp)
|
||||
{
|
||||
switch (exp->type) {
|
||||
case AST_IDENTIFIER:
|
||||
emitstring(J, F, OP_VAR, exp->string);
|
||||
break;
|
||||
case EXP_INDEX:
|
||||
cexp(J, F, exp->a);
|
||||
cexp(J, F, exp->b);
|
||||
emit(J, F, OP_INDEX);
|
||||
break;
|
||||
case EXP_MEMBER:
|
||||
cexp(J, F, exp->a);
|
||||
emitstring(J, F, OP_MEMBER, exp->b->string);
|
||||
break;
|
||||
default:
|
||||
jsC_error(J, exp, "invalid l-value in assignment");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void assignop(JF, js_Ast *exp, int opcode)
|
||||
{
|
||||
clval(J, F, exp->a);
|
||||
emit(J, F, OP_DUPLOAD);
|
||||
cexp(J, F, exp->b);
|
||||
emit(J, F, opcode);
|
||||
emit(J, F, OP_STORE);
|
||||
}
|
||||
|
||||
static void cexp(JF, js_Ast *exp)
|
||||
{
|
||||
int n;
|
||||
|
||||
switch (exp->type) {
|
||||
case AST_IDENTIFIER:
|
||||
emitstring(J, F, OP_VAR, exp->string);
|
||||
emit(J, F, OP_LOAD);
|
||||
break;
|
||||
|
||||
case AST_NUMBER: emitnumber(J, F, OP_CONST, exp->number); break;
|
||||
case AST_STRING: emitstring(J, F, OP_CONST, exp->string); break;
|
||||
case EXP_UNDEF: emit(J, F, OP_UNDEF); break;
|
||||
case EXP_NULL: emit(J, F, OP_NULL); break;
|
||||
case EXP_TRUE: emit(J, F, OP_TRUE); break;
|
||||
case EXP_FALSE: emit(J, F, OP_FALSE); break;
|
||||
case EXP_THIS: emit(J, F, OP_THIS); break;
|
||||
|
||||
case EXP_OBJECT:
|
||||
emit(J, F, OP_OBJECT);
|
||||
cobject(J, F, exp->a);
|
||||
break;
|
||||
|
||||
case EXP_ARRAY:
|
||||
emit(J, F, OP_ARRAY);
|
||||
carray(J, F, exp->a);
|
||||
break;
|
||||
|
||||
case EXP_INDEX:
|
||||
cexp(J, F, exp->a);
|
||||
cexp(J, F, exp->b);
|
||||
emit(J, F, OP_INDEX);
|
||||
emit(J, F, OP_LOAD);
|
||||
break;
|
||||
|
||||
case EXP_MEMBER:
|
||||
cexp(J, F, exp->a);
|
||||
emitstring(J, F, OP_MEMBER, exp->b->string);
|
||||
emit(J, F, OP_LOAD);
|
||||
break;
|
||||
|
||||
case EXP_CALL:
|
||||
cexp(J, F, exp->a);
|
||||
n = cargs(J, F, exp->b);
|
||||
emit(J, F, OP_CALL);
|
||||
emit(J, F, n);
|
||||
break;
|
||||
|
||||
case EXP_NEW:
|
||||
cexp(J, F, exp->a);
|
||||
n = cargs(J, F, exp->b);
|
||||
emit(J, F, OP_NEW);
|
||||
emit(J, F, n);
|
||||
break;
|
||||
|
||||
case EXP_VOID:
|
||||
cexp(J, F, exp->a);
|
||||
emit(J, F, OP_POP);
|
||||
emit(J, F, OP_UNDEF);
|
||||
break;
|
||||
|
||||
case EXP_TYPEOF: unary(J, F, exp, OP_TYPEOF); break;
|
||||
case EXP_POS: unary(J, F, exp, OP_POS); break;
|
||||
case EXP_NEG: unary(J, F, exp, OP_NEG); break;
|
||||
case EXP_BITNOT: unary(J, F, exp, OP_BITNOT); break;
|
||||
case EXP_LOGNOT: unary(J, F, exp, OP_LOGNOT); break;
|
||||
|
||||
case EXP_PREINC: clval(J, F, exp->a); emit(J, F, OP_PREINC); break;
|
||||
case EXP_PREDEC: clval(J, F, exp->a); emit(J, F, OP_PREDEC); break;
|
||||
case EXP_POSTINC: clval(J, F, exp->a); emit(J, F, OP_POSTINC); break;
|
||||
case EXP_POSTDEC: clval(J, F, exp->a); emit(J, F, OP_POSTDEC); break;
|
||||
|
||||
case EXP_LOGOR: binary(J, F, exp, OP_LOGOR); break;
|
||||
case EXP_LOGAND: binary(J, F, exp, OP_LOGAND); break;
|
||||
case EXP_BITOR: binary(J, F, exp, OP_BITOR); break;
|
||||
case EXP_BITXOR: binary(J, F, exp, OP_BITXOR); break;
|
||||
case EXP_BITAND: binary(J, F, exp, OP_BITAND); break;
|
||||
case EXP_EQ: binary(J, F, exp, OP_EQ); break;
|
||||
case EXP_NE: binary(J, F, exp, OP_NE); break;
|
||||
case EXP_EQ3: binary(J, F, exp, OP_EQ3); break;
|
||||
case EXP_NE3: binary(J, F, exp, OP_NE3); break;
|
||||
case EXP_LT: binary(J, F, exp, OP_LT); break;
|
||||
case EXP_GT: binary(J, F, exp, OP_GT); break;
|
||||
case EXP_LE: binary(J, F, exp, OP_LE); break;
|
||||
case EXP_GE: binary(J, F, exp, OP_GE); break;
|
||||
case EXP_INSTANCEOF: binary(J, F, exp, OP_INSTANCEOF); break;
|
||||
case EXP_IN: binary(J, F, exp, OP_IN); break;
|
||||
case EXP_SHL: binary(J, F, exp, OP_SHL); break;
|
||||
case EXP_SHR: binary(J, F, exp, OP_SHR); break;
|
||||
case EXP_USHR: binary(J, F, exp, OP_USHR); break;
|
||||
case EXP_ADD: binary(J, F, exp, OP_ADD); break;
|
||||
case EXP_SUB: binary(J, F, exp, OP_SUB); break;
|
||||
case EXP_MUL: binary(J, F, exp, OP_MUL); break;
|
||||
case EXP_DIV: binary(J, F, exp, OP_DIV); break;
|
||||
case EXP_MOD: binary(J, F, exp, OP_MOD); break;
|
||||
|
||||
case EXP_ASS:
|
||||
clval(J, F, exp->a);
|
||||
cexp(J, F, exp->b);
|
||||
emit(J, F, OP_STORE);
|
||||
break;
|
||||
|
||||
case EXP_ASS_MUL: assignop(J, F, exp, OP_MUL); break;
|
||||
case EXP_ASS_DIV: assignop(J, F, exp, OP_DIV); break;
|
||||
case EXP_ASS_MOD: assignop(J, F, exp, OP_MOD); break;
|
||||
case EXP_ASS_ADD: assignop(J, F, exp, OP_ADD); break;
|
||||
case EXP_ASS_SUB: assignop(J, F, exp, OP_SUB); break;
|
||||
case EXP_ASS_SHL: assignop(J, F, exp, OP_SHL); break;
|
||||
case EXP_ASS_SHR: assignop(J, F, exp, OP_SHR); break;
|
||||
case EXP_ASS_USHR: assignop(J, F, exp, OP_USHR); break;
|
||||
case EXP_ASS_BITAND: assignop(J, F, exp, OP_BITAND); break;
|
||||
case EXP_ASS_BITXOR: assignop(J, F, exp, OP_BITXOR); break;
|
||||
case EXP_ASS_BITOR: assignop(J, F, exp, OP_BITOR); break;
|
||||
|
||||
case EXP_COMMA:
|
||||
cexp(J, F, exp->a);
|
||||
emit(J, F, OP_POP);
|
||||
cexp(J, F, exp->b);
|
||||
break;
|
||||
|
||||
default:
|
||||
jsC_error(J, exp, "unknown expression");
|
||||
}
|
||||
}
|
||||
|
||||
static void cvardec(JF, js_Ast *vardec)
|
||||
{
|
||||
if (vardec->b)
|
||||
cexp(J, F, vardec->b);
|
||||
else
|
||||
emit(J, F, OP_UNDEF);
|
||||
emitstring(J, F, OP_DEFVAR, vardec->a->string);
|
||||
}
|
||||
|
||||
static void cvardeclist(JF, js_Ast *list)
|
||||
{
|
||||
while (list) {
|
||||
cvardec(J, F, list->a);
|
||||
list = list->b;
|
||||
}
|
||||
}
|
||||
|
||||
static int emitjump(JF, int opcode)
|
||||
{
|
||||
int addr = F->len + 1;
|
||||
emit(J, F, opcode);
|
||||
emit(J, F, 0);
|
||||
emit(J, F, 0);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void emitlabel(JF, int addr)
|
||||
{
|
||||
int dest = F->len;
|
||||
F->code[addr+0] = (dest >> 8) & 0xFF;
|
||||
F->code[addr+1] = (dest) & 0xFF;
|
||||
}
|
||||
|
||||
static void cstm(JF, js_Ast *stm)
|
||||
{
|
||||
int lelse, lend;
|
||||
|
||||
switch (stm->type) {
|
||||
case STM_BLOCK:
|
||||
cstmlist(J, F, stm->a);
|
||||
break;
|
||||
|
||||
case STM_NOP:
|
||||
break;
|
||||
|
||||
case STM_VAR:
|
||||
cvardeclist(J, F, stm->a);
|
||||
break;
|
||||
|
||||
case STM_IF:
|
||||
cexp(J, F, stm->a);
|
||||
lelse = emitjump(J, F, OP_JFALSE);
|
||||
cstm(J, F, stm->b);
|
||||
emitlabel(J, F, lelse);
|
||||
if (stm->c) {
|
||||
lend = emitjump(J, F, OP_JUMP);
|
||||
cstm(J, F, stm->c);
|
||||
emitlabel(J, F, lend);
|
||||
}
|
||||
break;
|
||||
|
||||
case STM_RETURN:
|
||||
if (stm->a)
|
||||
cexp(J, F, stm->a);
|
||||
else
|
||||
emit(J, F, OP_UNDEF);
|
||||
emit(J, F, OP_RETURN);
|
||||
break;
|
||||
|
||||
case STM_WITH:
|
||||
cexp(J, F, stm->a);
|
||||
emit(J, F, OP_PUSHWITH);
|
||||
cstm(J, F, stm->b);
|
||||
emit(J, F, OP_POPWITH);
|
||||
break;
|
||||
|
||||
// switch
|
||||
// throw, try
|
||||
// label
|
||||
|
||||
case STM_THROW:
|
||||
cexp(J, F, stm->a);
|
||||
emit(J, F, OP_THROW);
|
||||
break;
|
||||
|
||||
case STM_DEBUGGER:
|
||||
emit(J, F, OP_DEBUGGER);
|
||||
break;
|
||||
|
||||
default:
|
||||
cexp(J, F, stm);
|
||||
emit(J, F, OP_POP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cstmlist(JF, js_Ast *list)
|
||||
{
|
||||
while (list) {
|
||||
cstm(J, F, list->a);
|
||||
list = list->b;
|
||||
}
|
||||
}
|
||||
|
||||
static js_Function *newfun(js_State *J)
|
||||
{
|
||||
js_Function *F = malloc(sizeof(js_Function));
|
||||
|
||||
F->cap = 256;
|
||||
F->len = 0;
|
||||
F->code = malloc(F->cap);
|
||||
|
||||
F->kcap = 16;
|
||||
F->klen = 0;
|
||||
F->klist = malloc(F->kcap * sizeof(js_Value));
|
||||
|
||||
F->next = J->fun;
|
||||
J->fun = F;
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
static void freefun(js_State *J, js_Function *F)
|
||||
{
|
||||
free(F->klist);
|
||||
free(F->code);
|
||||
free(F);
|
||||
}
|
||||
|
||||
void jsC_freecompile(js_State *J)
|
||||
{
|
||||
js_Function *F = J->fun;
|
||||
while (F) {
|
||||
js_Function *next = F->next;
|
||||
freefun(J, F);
|
||||
F = next;
|
||||
}
|
||||
J->fun = NULL;
|
||||
}
|
||||
|
||||
int jsC_error(js_State *J, js_Ast *node, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "%s:%d: error: ", J->filename, node->line);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
longjmp(J->jb, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
js_Function *jsC_compile(js_State *J, js_Ast *prog)
|
||||
{
|
||||
js_Function *F;
|
||||
|
||||
if (setjmp(J->jb)) {
|
||||
jsC_freecompile(J);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
F = newfun(J);
|
||||
cstmlist(J, F, prog);
|
||||
|
||||
emit(J, F, OP_UNDEF);
|
||||
emit(J, F, OP_RETURN);
|
||||
|
||||
J->fun = NULL;
|
||||
return F;
|
||||
}
|
||||
|
||||
97
jscompile.h
Normal file
97
jscompile.h
Normal file
@@ -0,0 +1,97 @@
|
||||
#ifndef js_compile_h
|
||||
#define js_compile_h
|
||||
|
||||
enum
|
||||
{
|
||||
OP_CONST,
|
||||
OP_UNDEF,
|
||||
OP_NULL,
|
||||
OP_TRUE,
|
||||
OP_FALSE,
|
||||
OP_THIS,
|
||||
|
||||
OP_ARRAY,
|
||||
OP_ARRAYPUT,
|
||||
OP_OBJECT,
|
||||
OP_OBJECTPUT,
|
||||
|
||||
OP_DEFVAR,
|
||||
OP_VAR,
|
||||
OP_INDEX,
|
||||
OP_MEMBER,
|
||||
OP_LOAD,
|
||||
OP_DUPLOAD,
|
||||
OP_STORE,
|
||||
|
||||
OP_CALL,
|
||||
OP_NEW,
|
||||
OP_CLOSURE,
|
||||
|
||||
OP_DELETE,
|
||||
OP_VOID,
|
||||
OP_TYPEOF,
|
||||
OP_PREINC,
|
||||
OP_POSTINC,
|
||||
OP_PREDEC,
|
||||
OP_POSTDEC,
|
||||
OP_POS,
|
||||
OP_NEG,
|
||||
OP_BITNOT,
|
||||
OP_LOGNOT,
|
||||
|
||||
OP_LOGOR,
|
||||
OP_LOGAND,
|
||||
OP_BITOR,
|
||||
OP_BITXOR,
|
||||
OP_BITAND,
|
||||
OP_EQ,
|
||||
OP_NE,
|
||||
OP_EQ3,
|
||||
OP_NE3,
|
||||
OP_LT,
|
||||
OP_GT,
|
||||
OP_LE,
|
||||
OP_GE,
|
||||
OP_INSTANCEOF,
|
||||
OP_IN,
|
||||
OP_SHL,
|
||||
OP_SHR,
|
||||
OP_USHR,
|
||||
OP_ADD,
|
||||
OP_SUB,
|
||||
OP_MUL,
|
||||
OP_DIV,
|
||||
OP_MOD,
|
||||
|
||||
OP_JUMP,
|
||||
OP_JTRUE,
|
||||
OP_JFALSE,
|
||||
|
||||
OP_TRY,
|
||||
OP_THROW,
|
||||
OP_RETURN,
|
||||
OP_PUSHWITH,
|
||||
OP_POPWITH,
|
||||
OP_DEBUGGER,
|
||||
|
||||
OP_POP,
|
||||
};
|
||||
|
||||
struct js_Function
|
||||
{
|
||||
unsigned char *code;
|
||||
int cap, len;
|
||||
|
||||
js_Value *klist;
|
||||
int kcap, klen;
|
||||
|
||||
js_Function *next;
|
||||
};
|
||||
|
||||
js_Function *jsC_compile(js_State *J, js_Ast *prog);
|
||||
void jsC_freecompile(js_State *J);
|
||||
int jsC_error(js_State *J, js_Ast *node, const char *fmt, ...);
|
||||
void jsC_dumpvalue(js_State *J, js_Value v);
|
||||
void jsC_dumpfunction(js_State *J, js_Function *fun);
|
||||
|
||||
#endif
|
||||
91
jsdump.c
91
jsdump.c
@@ -1,9 +1,11 @@
|
||||
#include "js.h"
|
||||
#include "jsparse.h"
|
||||
#include "jscompile.h"
|
||||
#include "jsrun.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static const char *stype[] = {
|
||||
static const char *astname[] = {
|
||||
"list", "ident", "number", "string", "regexp", "undef", "null", "true",
|
||||
"false", "this", "array", "object", "prop_val", "prop_get", "prop_set",
|
||||
"index", "member", "call", "new", "funexp", "delete", "void", "typeof",
|
||||
@@ -15,8 +17,21 @@ static const char *stype[] = {
|
||||
"ass_ushr", "ass_bitand", "ass_bitxor", "ass_bitor", "comma",
|
||||
"var-init", "block", "fundec", "nop", "var", "if", "do-while", "while",
|
||||
"for", "for-var", "for-in", "for-in-var", "continue", "break",
|
||||
"return", "with", "switch", "throw", "try", "label", "case", "default",
|
||||
"debugger",
|
||||
"return", "with", "switch", "throw", "try", "debugger", "label",
|
||||
"case", "default",
|
||||
};
|
||||
|
||||
static const char *opname[] = {
|
||||
"const", "undef", "null", "true", "false", "this",
|
||||
"array", "arrayput",
|
||||
"object", "objectput",
|
||||
"defvar", "var", "index", "member", "load", "dupload", "store", "call", "new",
|
||||
"closure", "delete", "void", "typeof", "preinc", "postinc", "predec",
|
||||
"postdec", "pos", "neg", "bitnot", "lognot", "logor", "logand",
|
||||
"bitor", "bitxor", "bitand", "eq", "ne", "eq3", "ne3", "lt", "gt",
|
||||
"le", "ge", "instanceof", "in", "shl", "shr", "ushr", "add", "sub",
|
||||
"mul", "div", "mod", "jump", "jtrue", "jfalse", "try", "throw",
|
||||
"return", "pushwith", "popwith", "debugger", "pop",
|
||||
};
|
||||
|
||||
static void pstmlist(int d, js_Ast *list);
|
||||
@@ -499,7 +514,7 @@ void jsP_dumpsyntax(js_State *J, js_Ast *prog)
|
||||
pstmlist(-1, prog);
|
||||
else {
|
||||
pstm(0, prog);
|
||||
pc('\n');
|
||||
nl();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,7 +535,7 @@ static void snode(int d, js_Ast *node)
|
||||
}
|
||||
|
||||
pc('(');
|
||||
ps(stype[node->type]);
|
||||
ps(astname[node->type]);
|
||||
switch (node->type) {
|
||||
case AST_IDENTIFIER: pc(' '); ps(node->string); break;
|
||||
case AST_STRING: pc(' '); pstr(node->string); break;
|
||||
@@ -561,11 +576,11 @@ static void sblock(int d, js_Ast *list)
|
||||
snode(d+1, list->a);
|
||||
list = list->b;
|
||||
if (list) {
|
||||
pc('\n');
|
||||
nl();
|
||||
in(d+1);
|
||||
}
|
||||
}
|
||||
pc('\n'); in(d); pc(']');
|
||||
nl(); in(d); pc(']');
|
||||
}
|
||||
|
||||
void jsP_dumplist(js_State *J, js_Ast *prog)
|
||||
@@ -574,5 +589,65 @@ void jsP_dumplist(js_State *J, js_Ast *prog)
|
||||
sblock(0, prog);
|
||||
else
|
||||
snode(0, prog);
|
||||
pc('\n');
|
||||
nl();
|
||||
}
|
||||
|
||||
void jsC_dumpvalue(js_State *J, js_Value v)
|
||||
{
|
||||
switch (v.type) {
|
||||
case JS_TUNDEFINED: ps("undefined"); break;
|
||||
case JS_TNULL: ps("null"); break;
|
||||
case JS_TBOOLEAN: ps(v.u.boolean ? "true" : "false"); break;
|
||||
case JS_TNUMBER: printf("%.9g", v.u.number); break;
|
||||
case JS_TSTRING: pstr(v.u.string); break;
|
||||
case JS_TREGEXP: printf("<regexp %p>", v.u.p); break;
|
||||
case JS_TOBJECT: printf("<object %p>", v.u.p); break;
|
||||
|
||||
case JS_TFUNCTION: printf("<function %p>", v.u.p); break;
|
||||
case JS_TCFUNCTION: printf("<cfunction %p>", v.u.p); break;
|
||||
case JS_TCLOSURE: printf("<closure %p>", v.u.p); break;
|
||||
case JS_TARGUMENTS: printf("<arguments %p>", v.u.p); break;
|
||||
|
||||
case JS_TOBJSLOT: printf("<objslot %p>", v.u.p); break;
|
||||
}
|
||||
}
|
||||
|
||||
void jsC_dumpfunction(js_State *J, js_Function *fun)
|
||||
{
|
||||
unsigned char *p = fun->code;
|
||||
unsigned char *end = fun->code + fun->len;
|
||||
int dest;
|
||||
|
||||
printf("function with %d constants\n", fun->klen);
|
||||
|
||||
while (p < end) {
|
||||
int c = *p++;
|
||||
|
||||
printf("%04d: ", (int)(p - fun->code) - 1);
|
||||
ps(opname[c]);
|
||||
|
||||
switch (c) {
|
||||
case OP_CONST:
|
||||
case OP_OBJECTPUT:
|
||||
case OP_DEFVAR:
|
||||
case OP_VAR:
|
||||
case OP_MEMBER:
|
||||
pc(' ');
|
||||
jsC_dumpvalue(J, fun->klist[*p++]);
|
||||
break;
|
||||
case OP_CALL:
|
||||
case OP_NEW:
|
||||
printf(" %d", *p++);
|
||||
break;
|
||||
case OP_JUMP:
|
||||
case OP_JTRUE:
|
||||
case OP_JFALSE:
|
||||
dest = (*p++) << 8;
|
||||
dest += (*p++);
|
||||
printf(" %d", dest);
|
||||
break;
|
||||
}
|
||||
|
||||
nl();
|
||||
}
|
||||
}
|
||||
|
||||
13
jsload.c
13
jsload.c
@@ -1,13 +1,22 @@
|
||||
#include "js.h"
|
||||
#include "jsparse.h"
|
||||
#include "jscompile.h"
|
||||
#include "jsrun.h"
|
||||
|
||||
static int jsP_loadstring(js_State *J, const char *filename, const char *source)
|
||||
{
|
||||
js_Ast *prog = jsP_parse(J, filename, source);
|
||||
if (prog) {
|
||||
jsP_optimize(J, prog);
|
||||
// jsP_dumpsyntax(J, prog);
|
||||
js_Function *fun;
|
||||
//jsP_optimize(J, prog);
|
||||
//jsP_dumpsyntax(J, prog);
|
||||
jsP_dumplist(J, prog);
|
||||
fun = jsC_compile(J, prog);
|
||||
if (fun) {
|
||||
jsC_dumpfunction(J, fun);
|
||||
jsR_runfunction(J, fun);
|
||||
}
|
||||
jsC_freecompile(J);
|
||||
jsP_freeparse(J);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -114,10 +114,11 @@ enum
|
||||
STM_SWITCH,
|
||||
STM_THROW,
|
||||
STM_TRY,
|
||||
STM_DEBUGGER,
|
||||
|
||||
STM_LABEL,
|
||||
STM_CASE,
|
||||
STM_DEFAULT,
|
||||
STM_DEBUGGER,
|
||||
};
|
||||
|
||||
js_Ast *jsP_parse(js_State *J, const char *filename, const char *source);
|
||||
|
||||
149
jsrun.c
Normal file
149
jsrun.c
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "js.h"
|
||||
#include "jscompile.h"
|
||||
#include "jsrun.h"
|
||||
#include "jsstate.h"
|
||||
|
||||
static js_Value stack[256];
|
||||
static int top = 0;
|
||||
|
||||
static inline int i32(double d)
|
||||
{
|
||||
double two32 = 4294967296.0;
|
||||
double two31 = 2147483648.0;
|
||||
|
||||
if (!isfinite(d) || d == 0)
|
||||
return 0;
|
||||
|
||||
d = fmod(d, two32);
|
||||
d = d >= 0 ? floor(d) : ceil(d) + two32;
|
||||
if (d >= two31)
|
||||
return d - two32;
|
||||
else
|
||||
return d;
|
||||
}
|
||||
|
||||
static inline unsigned int u32(double d)
|
||||
{
|
||||
return i32(d);
|
||||
}
|
||||
|
||||
static inline void push(js_State *J, js_Value v)
|
||||
{
|
||||
stack[top++] = v;
|
||||
}
|
||||
|
||||
static inline js_Value pop(js_State *J)
|
||||
{
|
||||
return stack[--top];
|
||||
}
|
||||
|
||||
static inline void pushnumber(js_State *J, double number)
|
||||
{
|
||||
js_Value v;
|
||||
v.type = JS_TNUMBER;
|
||||
v.u.number = number;
|
||||
push(J, v);
|
||||
}
|
||||
|
||||
static inline double popnumber(js_State *J)
|
||||
{
|
||||
js_Value v = pop(J);
|
||||
if (v.type == JS_TNUMBER)
|
||||
return v.u.number;
|
||||
if (v.type == JS_TSTRING)
|
||||
return strtod(v.u.string, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void pushundefined(js_State *J)
|
||||
{
|
||||
js_Value v;
|
||||
v.type = JS_TUNDEFINED;
|
||||
push(J, v);
|
||||
}
|
||||
|
||||
static inline void pushnull(js_State *J)
|
||||
{
|
||||
js_Value v;
|
||||
v.type = JS_TNULL;
|
||||
push(J, v);
|
||||
}
|
||||
|
||||
static inline void pushboolean(js_State *J, int boolean)
|
||||
{
|
||||
js_Value v;
|
||||
v.type = JS_TBOOLEAN;
|
||||
v.u.boolean = boolean;
|
||||
push(J, v);
|
||||
}
|
||||
|
||||
static inline int popboolean(js_State *J)
|
||||
{
|
||||
js_Value v = pop(J);
|
||||
if (v.type == JS_TBOOLEAN)
|
||||
return v.u.boolean;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dumpstack(js_State *J)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < top; i++) {
|
||||
printf("stack %d: ", i);
|
||||
jsC_dumpvalue(J, stack[i]);
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
#define UNARY(X) a = popnumber(J); pushnumber(J, X)
|
||||
#define BINARY(X) b = popnumber(J); a = popnumber(J); pushnumber(J, X)
|
||||
|
||||
static void runfun(js_State *J, js_Function *F)
|
||||
{
|
||||
unsigned char *pc = F->code;
|
||||
int opcode, i;
|
||||
double a, b;
|
||||
|
||||
while (1) {
|
||||
opcode = *pc++;
|
||||
switch (opcode) {
|
||||
case OP_CONST:
|
||||
i = *pc++;
|
||||
push(J, F->klist[i]);
|
||||
break;
|
||||
|
||||
case OP_UNDEF: pushundefined(J); break;
|
||||
case OP_NULL: pushnull(J); break;
|
||||
case OP_TRUE: pushboolean(J, 1); break;
|
||||
case OP_FALSE: pushboolean(J, 0); break;
|
||||
|
||||
case OP_POS: UNARY(a); break;
|
||||
case OP_NEG: UNARY(-a); break;
|
||||
case OP_BITNOT: UNARY(~i32(a)); break;
|
||||
|
||||
case OP_ADD: BINARY(a + b); break;
|
||||
case OP_SUB: BINARY(a - b); break;
|
||||
case OP_MUL: BINARY(a * b); break;
|
||||
case OP_DIV: BINARY(a / b); break;
|
||||
case OP_MOD: BINARY(fmod(a, b)); break;
|
||||
case OP_SHL: BINARY(i32(a) << (u32(b) & 0x1F)); break;
|
||||
case OP_SHR: BINARY(i32(a) >> (u32(b) & 0x1F)); break;
|
||||
case OP_USHR: BINARY(u32(a) >> (u32(b) & 0x1F)); break;
|
||||
case OP_BITAND: BINARY(i32(a) & i32(b)); break;
|
||||
case OP_BITXOR: BINARY(i32(a) ^ i32(b)); break;
|
||||
case OP_BITOR: BINARY(i32(a) | i32(b)); break;
|
||||
|
||||
case OP_RETURN: return;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "illegal instruction: %d\n", opcode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void jsR_runfunction(js_State *J, js_Function *F)
|
||||
{
|
||||
runfun(J, F);
|
||||
dumpstack(J);
|
||||
}
|
||||
35
jsrun.h
Normal file
35
jsrun.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef js_run_h
|
||||
#define js_run_h
|
||||
|
||||
enum js_ValueType {
|
||||
JS_TUNDEFINED,
|
||||
JS_TNULL,
|
||||
JS_TBOOLEAN,
|
||||
JS_TNUMBER,
|
||||
JS_TSTRING,
|
||||
JS_TREGEXP,
|
||||
JS_TOBJECT,
|
||||
|
||||
JS_TFUNCTION,
|
||||
JS_TCFUNCTION,
|
||||
JS_TCLOSURE,
|
||||
JS_TARGUMENTS,
|
||||
|
||||
JS_TOBJSLOT,
|
||||
};
|
||||
|
||||
struct js_Value
|
||||
{
|
||||
union {
|
||||
double number;
|
||||
const char *string;
|
||||
int boolean;
|
||||
void *p;
|
||||
} u;
|
||||
int flag;
|
||||
js_ValueType type;
|
||||
};
|
||||
|
||||
void jsR_runfunction(js_State *J, js_Function *F);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user