added the jump_backward_if_true instruction.

added more do-while handling code
This commit is contained in:
hyunghwan.chung 2017-01-30 16:48:42 +00:00
parent 341966e373
commit 22013650bb
8 changed files with 360 additions and 96 deletions

View File

@ -176,14 +176,29 @@ class MyObject(Object)
a := a + 100000000000000. a := a + 100000000000000.
}.*) }.*)
(*
a := 5. a := 5.
while (true) a := while (true)
{ {
a := a + 1. a := a + 1.
if (a > 20) { break }. ##if (a > 20) { break if (true) { break. }. }.
if (a > 20) {
^if (true) { break } else {10}. ## return gets ignored for break.
}.
a dump. a dump.
}. }.
a dump.*)
a := 5.
do {
a := do {
('in loop.....' & a asString) dump.
if (a > 5) { break }.
a := a + 1.
} while(a < 10).
} while (false).
a dump.
## these should be elimited by the compiler.
nil. nil.
1. 1.
0. 0.
@ -192,6 +207,8 @@ class MyObject(Object)
thisContext. thisContext.
nil. nil.
nil. nil.
## end of elimination.
'---------- END ------------' dump. '---------- END ------------' dump.
##Processor sleepFor: 20. ##Processor sleepFor: 20.
} }

View File

@ -100,6 +100,7 @@ class MyObject(Object)
'literal expected' 'literal expected'
'break or continue not within a loop' 'break or continue not within a loop'
'break or continue within a block' 'break or continue within a block'
'while expected'
). ).
f := Stdio open: 'generr.out' for: 'w'. f := Stdio open: 'generr.out' for: 'w'.

View File

@ -83,6 +83,7 @@ static struct voca_t
{ 8, { 'c','o','n','t','i','n','u','e' } }, { 8, { 'c','o','n','t','i','n','u','e' } },
{ 3, { 'd','c','l' } }, { 3, { 'd','c','l' } },
{ 7, { 'd','e','c','l','a','r','e' } }, { 7, { 'd','e','c','l','a','r','e' } },
{ 2, { 'd','o' } },
{ 4, { 'e','l','s','e' } }, { 4, { 'e','l','s','e' } },
{ 5, { 'e','l','s','i','f' } }, { 5, { 'e','l','s','i','f' } },
{ 6, { 'e','n','s','u','r','e', } }, { 6, { 'e','n','s','u','r','e', } },
@ -127,6 +128,7 @@ enum voca_id_t
VOCA_CONTINUE, VOCA_CONTINUE,
VOCA_DCL, VOCA_DCL,
VOCA_DECLARE, VOCA_DECLARE,
VOCA_DO,
VOCA_ELSE, VOCA_ELSE,
VOCA_ELSIF, VOCA_ELSIF,
VOCA_ENSURE, VOCA_ENSURE,
@ -245,11 +247,13 @@ static MOO_INLINE int is_identchar (moo_ooci_t c)
return is_alnumchar(c) || c == '_'; return is_alnumchar(c) || c == '_';
} }
#if 0
static MOO_INLINE int is_closing_char (moo_ooci_t c) static MOO_INLINE int is_closing_char (moo_ooci_t c)
{ {
switch (c) switch (c)
{ {
case '.': case '.':
case '}':
case ']': case ']':
case ')': case ')':
case ';': case ';':
@ -261,6 +265,7 @@ static MOO_INLINE int is_closing_char (moo_ooci_t c)
return 0; return 0;
} }
} }
#endif
static MOO_INLINE int is_word (const moo_oocs_t* oocs, voca_id_t id) static MOO_INLINE int is_word (const moo_oocs_t* oocs, voca_id_t id)
{ {
@ -1061,6 +1066,10 @@ static int get_ident (moo_t* moo, moo_ooci_t char_read_ahead)
{ {
SET_TOKEN_TYPE (moo, MOO_IOTOK_WHILE); SET_TOKEN_TYPE (moo, MOO_IOTOK_WHILE);
} }
else if (is_token_word(moo, VOCA_DO))
{
SET_TOKEN_TYPE (moo, MOO_IOTOK_DO);
}
else if (is_token_word(moo, VOCA_BREAK)) else if (is_token_word(moo, VOCA_BREAK))
{ {
SET_TOKEN_TYPE (moo, MOO_IOTOK_BREAK); SET_TOKEN_TYPE (moo, MOO_IOTOK_BREAK);
@ -1945,10 +1954,6 @@ static int emit_single_param_instruction (moo_t* moo, int cmd, moo_oow_t param_1
case BCODE_PUSH_OBJECT_0: case BCODE_PUSH_OBJECT_0:
case BCODE_STORE_INTO_OBJECT_0: case BCODE_STORE_INTO_OBJECT_0:
case BCODE_POP_INTO_OBJECT_0: case BCODE_POP_INTO_OBJECT_0:
case BCODE_JUMP_FORWARD_0:
case BCODE_JUMP_BACKWARD_0:
case BCODE_JUMP_FORWARD_IF_FALSE_0:
case BCODE_JUMP_BACKWARD_IF_FALSE_0:
if (param_1 < 4) if (param_1 < 4)
{ {
/* low 2 bits to hold the parameter */ /* low 2 bits to hold the parameter */
@ -1957,13 +1962,40 @@ static int emit_single_param_instruction (moo_t* moo, int cmd, moo_oow_t param_1
} }
else else
{ {
/* convert the code to a long version */ /* convert the instruction to a long version (_X) */
bc = cmd | 0x80; bc = cmd | 0x80;
goto write_long; goto write_long;
} }
case BCODE_JUMP_FORWARD_0:
case BCODE_JUMP_BACKWARD_0:
case BCODE_JUMP_FORWARD_IF_FALSE_0:
case BCODE_JUMP_BACKWARD_IF_FALSE_0:
case BCODE_JUMP_BACKWARD_IF_TRUE_0:
if (param_1 < 4)
{
/* low 2 bits to hold the parameter */
bc = (moo_oob_t)(cmd & 0xFC) | (moo_oob_t)param_1;
goto write_short;
}
else
{
/* convert the instruction to a long version (_X) */
bc = cmd | 0x80;
if (param_1 > MAX_CODE_JUMP)
{
cmd = cmd + 1; /* convert to a JUMP2 instruction */
param_1 = param_1 - MAX_CODE_JUMP;
}
goto write_long;
}
case BCODE_JUMP2_FORWARD: case BCODE_JUMP2_FORWARD:
case BCODE_JUMP2_BACKWARD: case BCODE_JUMP2_BACKWARD:
case BCODE_JUMP2_FORWARD_IF_FALSE:
case BCODE_JUMP2_BACKWARD_IF_FALSE:
case BCODE_JUMP2_BACKWARD_IF_TRUE:
case BCODE_PUSH_INTLIT: case BCODE_PUSH_INTLIT:
case BCODE_PUSH_NEGINTLIT: case BCODE_PUSH_NEGINTLIT:
case BCODE_PUSH_CHARLIT: case BCODE_PUSH_CHARLIT:
@ -1995,7 +2027,6 @@ write_long:
return 0; return 0;
} }
static int emit_double_param_instruction (moo_t* moo, int cmd, moo_oow_t param_1, moo_oow_t param_2) static int emit_double_param_instruction (moo_t* moo, int cmd, moo_oow_t param_1, moo_oow_t param_2)
{ {
moo_oob_t bc; moo_oob_t bc;
@ -2106,15 +2137,64 @@ static int emit_push_character_literal (moo_t* moo, moo_ooch_t ch)
return 0; return 0;
} }
static MOO_INLINE int emit_backward_jump_instruction (moo_t* moo, moo_oow_t offset) static MOO_INLINE int emit_backward_jump_instruction (moo_t* moo, int cmd, moo_oow_t offset)
{ {
moo_oow_t adj; moo_oow_t adj;
/* BCODE_JUMP_BACKWARD_0 can use low 2 bits to encode the jump offset.
* so it can encode 0, 1, 2, 3. the instruction itself is 1 byte long.
* the 0, 1, 2 can get emitted u*/
adj = (offset < 3)? 1: (MOO_BCODE_LONG_PARAM_SIZE + 1);
return emit_single_param_instruction (moo, BCODE_JUMP_BACKWARD_0, offset + adj);
MOO_ASSERT (moo, cmd == BCODE_JUMP_BACKWARD_0 ||
cmd == BCODE_JUMP_BACKWARD_IF_FALSE_0 ||
cmd == BCODE_JUMP_BACKWARD_IF_TRUE_0);
/* the short BCODE_JUMP_BACKWARD instructions use low 2 bits to encode
* the jump offset. so it can encode 0, 1, 2, 3. the instruction itself
* is 1 byte long. the offset value of 0, 1, 2 can get encoded into the
* instruction, which result in 1, 2, 3 when combined with the length 1
* of the instruction itself */
adj = (offset < 3)? 1: (MOO_BCODE_LONG_PARAM_SIZE + 1);
return emit_single_param_instruction (moo, cmd, offset + adj);
}
static int patch_long_forward_jump_instruction (moo_t* moo, moo_oow_t jip, moo_oow_t jt, moo_oob_t jump2_inst, moo_ioloc_t* errloc)
{
moo_oow_t code_size;
moo_oow_t jump_offset;
/* jip - jump instruction pointer, jt - jump target *
*
* when this jump instruction is executed, the instruction pointer advances
* to the next instruction. so the actual jump size gets offset by the size
* of this jump instruction. MOO_BCODE_LONG_PARAM_SIZE + 1 is the size of
* the long JUMP_FORWARD instruction */
code_size = jt - jip - (MOO_BCODE_LONG_PARAM_SIZE + 1);
if (code_size > MAX_CODE_JUMP * 2)
{
/* TODO: change error code or get it as a parameter */
set_syntax_error (moo, MOO_SYNERR_BLKFLOOD, errloc, MOO_NULL);
return -1;
}
if (code_size > MAX_CODE_JUMP)
{
/* switch to JUMP2 instruction to allow a bigger jump offset.
* up to twice MAX_CODE_JUMP only */
moo->c->mth.code.ptr[jip] = jump2_inst;
jump_offset = code_size - MAX_CODE_JUMP;
}
else
{
jump_offset = code_size;
}
#if (MOO_BCODE_LONG_PARAM_SIZE == 2)
moo->c->mth.code.ptr[jip + 1] = jump_offset >> 8;
moo->c->mth.code.ptr[jip + 2] = jump_offset & 0xFF;
#else
moo->c->mth.code.ptr[jip + 1] = jump_offset;
#endif
return 0;
} }
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* Compiler * Compiler
@ -3348,46 +3428,7 @@ static int store_tmpr_count_for_block (moo_t* moo, moo_oow_t tmpr_count)
return 0; return 0;
} }
static int patch_long_forward_jump_instruction (moo_t* moo, moo_oow_t jip, moo_oob_t jump2_inst, moo_ioloc_t* errloc) static int push_loop (moo_t* moo, moo_loop_type_t type, moo_oow_t startpos)
{
moo_oow_t code_size;
moo_oow_t jump_offset;
/* when this jump instruction is executed, the instruction pointer advances
* to the next instruction. so the actual jump size gets offset by the size
* of this jump instruction. MOO_BCODE_LONG_PARAM_SIZE + 1 is the size of
* the long JUMP_FORWARD instruction */
code_size = moo->c->mth.code.len - jip - (MOO_BCODE_LONG_PARAM_SIZE + 1);
if (code_size > MAX_CODE_JUMP * 2)
{
/* TODO: change error code or get it as a parameter */
set_syntax_error (moo, MOO_SYNERR_BLKFLOOD, errloc, MOO_NULL);
return -1;
}
if (code_size > MAX_CODE_JUMP)
{
/* switch to JUMP2 instruction to allow a bigger jump offset.
* up to twice MAX_CODE_JUMP only */
moo->c->mth.code.ptr[jip] = jump2_inst;
jump_offset = code_size - MAX_CODE_JUMP;
}
else
{
jump_offset = code_size;
}
#if (MOO_BCODE_LONG_PARAM_SIZE == 2)
moo->c->mth.code.ptr[jip + 1] = jump_offset >> 8;
moo->c->mth.code.ptr[jip + 2] = jump_offset & 0xFF;
#else
moo->c->mth.code.ptr[jip + 1] = jump_offset;
#endif
return 0;
}
static int push_loop (moo_t* moo, moo_oow_t startpos)
{ {
moo_loop_t* loop; moo_loop_t* loop;
@ -3395,6 +3436,8 @@ static int push_loop (moo_t* moo, moo_oow_t startpos)
if (!loop) return -1; if (!loop) return -1;
init_oow_pool (moo, &loop->break_ip_pool); init_oow_pool (moo, &loop->break_ip_pool);
init_oow_pool (moo, &loop->continue_ip_pool);
loop->type = type;
loop->startpos = startpos; loop->startpos = startpos;
loop->next = moo->c->mth.loop; loop->next = moo->c->mth.loop;
moo->c->mth.loop = loop; moo->c->mth.loop = loop;
@ -3402,37 +3445,56 @@ static int push_loop (moo_t* moo, moo_oow_t startpos)
return 0; return 0;
} }
static int pop_loop (moo_t* moo, int patch_break) static int update_loop_jumps (moo_t* moo, moo_oow_pool_t* pool, moo_oow_t jt)
{
/* patch the jump instructions emitted for 'break' */
moo_oow_pool_chunk_t* chunk;
moo_oow_t i, j;
for (chunk = pool->head, i = 0; chunk; chunk = chunk->next)
{
for (j = 0; j < MOO_COUNTOF(pool->static_chunk.buf) && i < pool->count; j++)
{
if (patch_long_forward_jump_instruction (moo, chunk->buf[j], jt, BCODE_JUMP2_FORWARD, MOO_NULL) <= -1) return -1;
i++;
}
}
return 0;
}
static MOO_INLINE int update_loop_breaks (moo_t* moo, moo_oow_t jt)
{
return update_loop_jumps (moo, &moo->c->mth.loop->break_ip_pool, jt);
}
static MOO_INLINE int update_loop_continues (moo_t* moo, moo_oow_t jt)
{
return update_loop_jumps (moo, &moo->c->mth.loop->continue_ip_pool, jt);
}
static MOO_INLINE moo_loop_t* unlink_loop (moo_t* moo)
{ {
moo_loop_t* loop; moo_loop_t* loop;
/* this function must be called when moo->c->mth.code.len is pointing
* to the intended target position because patch_long_forward_jump_instruction()
* patches jumps using the current value in moo->c->mth.code.len */
MOO_ASSERT (moo, moo->c->mth.loop != MOO_NULL); MOO_ASSERT (moo, moo->c->mth.loop != MOO_NULL);
loop = moo->c->mth.loop; loop = moo->c->mth.loop;
moo->c->mth.loop = loop->next; moo->c->mth.loop = loop->next;
if (patch_break) return loop;
{ }
/* patch the jump instructions emitted for 'break' */
moo_oow_pool_chunk_t* chunk;
moo_oow_t i, j;
for (chunk = loop->break_ip_pool.head, i = 0; chunk; chunk = chunk->next)
{
for (j = 0; j < MOO_COUNTOF(loop->break_ip_pool.static_chunk.buf) && i < loop->break_ip_pool.count; j++)
{
if (patch_long_forward_jump_instruction (moo, chunk->buf[j], BCODE_JUMP2_FORWARD, MOO_NULL) <= -1) return -1;
i++;
}
}
}
static MOO_INLINE void free_loop (moo_t* moo, moo_loop_t* loop)
{
fini_oow_pool (moo, &loop->continue_ip_pool);
fini_oow_pool (moo, &loop->break_ip_pool); fini_oow_pool (moo, &loop->break_ip_pool);
moo_freemem (moo, loop); moo_freemem (moo, loop);
return 0; }
static MOO_INLINE void pop_loop (moo_t* moo)
{
free_loop (moo, unlink_loop (moo));
} }
static MOO_INLINE int inject_break_to_loop (moo_t* moo) static MOO_INLINE int inject_break_to_loop (moo_t* moo)
@ -3442,6 +3504,13 @@ static MOO_INLINE int inject_break_to_loop (moo_t* moo)
return 0; return 0;
} }
static MOO_INLINE int inject_continue_to_loop (moo_t* moo)
{
if (add_to_oow_pool (moo, &moo->c->mth.loop->continue_ip_pool, moo->c->mth.code.len) <= -1 ||
emit_single_param_instruction (moo, BCODE_JUMP_FORWARD_0, MAX_CODE_JUMP) <= -1) return -1;
return 0;
}
static int compile_block_expression (moo_t* moo) static int compile_block_expression (moo_t* moo)
{ {
moo_oow_t jump_inst_pos; moo_oow_t jump_inst_pos;
@ -3586,7 +3655,7 @@ static int compile_block_expression (moo_t* moo)
if (emit_byte_instruction(moo, BCODE_RETURN_FROM_BLOCK) <= -1) return -1; if (emit_byte_instruction(moo, BCODE_RETURN_FROM_BLOCK) <= -1) return -1;
if (patch_long_forward_jump_instruction (moo, jump_inst_pos, BCODE_JUMP2_FORWARD, &block_loc) <= -1) return -1; if (patch_long_forward_jump_instruction (moo, jump_inst_pos, moo->c->mth.code.len, BCODE_JUMP2_FORWARD, &block_loc) <= -1) return -1;
/* restore the temporary count */ /* restore the temporary count */
moo->c->mth.tmprs.len = saved_tmprs_len; moo->c->mth.tmprs.len = saved_tmprs_len;
@ -4395,8 +4464,8 @@ static int compile_braced_block (moo_t* moo)
/* handle a code block enclosed in { } */ /* handle a code block enclosed in { } */
/*TODO: support local variable declaration inside {} */ /*TODO: support local variable declaration inside {} */
moo_oow_t code_start; moo_oow_t code_start;
if (TOKEN_TYPE(moo) != MOO_IOTOK_LBRACE) if (TOKEN_TYPE(moo) != MOO_IOTOK_LBRACE)
{ {
set_syntax_error (moo, MOO_SYNERR_LBRACE, TOKEN_LOC(moo), TOKEN_NAME(moo)); set_syntax_error (moo, MOO_SYNERR_LBRACE, TOKEN_LOC(moo), TOKEN_NAME(moo));
@ -4496,7 +4565,7 @@ static int compile_if_expression (moo_t* moo)
GET_TOKEN (moo); GET_TOKEN (moo);
while (TOKEN_TYPE(moo) == MOO_IOTOK_ELSIF) while (TOKEN_TYPE(moo) == MOO_IOTOK_ELSIF)
{ {
if (patch_long_forward_jump_instruction (moo, jumptonext, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; if (patch_long_forward_jump_instruction (moo, jumptonext, moo->c->mth.code.len, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops;
GET_TOKEN (moo); /* get ( */ GET_TOKEN (moo); /* get ( */
if (compile_conditional(moo) <= -1) goto oops; if (compile_conditional(moo) <= -1) goto oops;
@ -4517,7 +4586,7 @@ static int compile_if_expression (moo_t* moo)
GET_TOKEN (moo); /* get the next token after } */ GET_TOKEN (moo); /* get the next token after } */
} }
if (patch_long_forward_jump_instruction (moo, jumptonext, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; if (patch_long_forward_jump_instruction (moo, jumptonext, moo->c->mth.code.len, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops;
if (TOKEN_TYPE(moo) == MOO_IOTOK_ELSE) if (TOKEN_TYPE(moo) == MOO_IOTOK_ELSE)
{ {
@ -4539,7 +4608,7 @@ static int compile_if_expression (moo_t* moo)
* call will never flood either. */ * call will never flood either. */
for (j = 0; j < MOO_COUNTOF(jumptoend.static_chunk.buf) && i < jumptoend.count; j++) for (j = 0; j < MOO_COUNTOF(jumptoend.static_chunk.buf) && i < jumptoend.count; j++)
{ {
if (patch_long_forward_jump_instruction (moo, jumptoend_chunk->buf[j], BCODE_JUMP2_FORWARD_IF_FALSE, &if_loc) <= -1) goto oops; if (patch_long_forward_jump_instruction (moo, jumptoend_chunk->buf[j], moo->c->mth.code.len, BCODE_JUMP2_FORWARD_IF_FALSE, &if_loc) <= -1) goto oops;
i++; i++;
} }
} }
@ -4561,7 +4630,7 @@ static int compile_while_expression (moo_t* moo)
MOO_ASSERT (moo, TOKEN_TYPE(moo) == MOO_IOTOK_WHILE); MOO_ASSERT (moo, TOKEN_TYPE(moo) == MOO_IOTOK_WHILE);
while_loc = *TOKEN_LOC(moo); while_loc = *TOKEN_LOC(moo);
GET_TOKEN (moo); /* get ( */ GET_TOKEN (moo); /* get (, verification is done inside compile_conditional() */
precondpos = moo->c->mth.code.len; precondpos = moo->c->mth.code.len;
if (compile_conditional (moo) <= -1) goto oops; if (compile_conditional (moo) <= -1) goto oops;
@ -4593,7 +4662,7 @@ static int compile_while_expression (moo_t* moo)
} }
/* remember information about this while loop. */ /* remember information about this while loop. */
if (push_loop (moo, precondpos) <= -1) goto oops; if (push_loop (moo, MOO_LOOP_WHILE, precondpos) <= -1) goto oops;
loop_pushed = 1; loop_pushed = 1;
GET_TOKEN (moo); /* get { */ GET_TOKEN (moo); /* get { */
@ -4617,7 +4686,7 @@ static int compile_while_expression (moo_t* moo)
} }
/* emit code to jump back to the condition */ /* emit code to jump back to the condition */
if (emit_backward_jump_instruction (moo, moo->c->mth.code.len - precondpos) <= -1) if (emit_backward_jump_instruction (moo, BCODE_JUMP_BACKWARD_0, moo->c->mth.code.len - precondpos) <= -1)
{ {
if (moo->errnum == MOO_ERANGE) if (moo->errnum == MOO_ERANGE)
{ {
@ -4631,7 +4700,7 @@ static int compile_while_expression (moo_t* moo)
if (cond_style != 1) if (cond_style != 1)
{ {
/* patch the jump instruction. */ /* patch the jump instruction. */
if (patch_long_forward_jump_instruction (moo, postcondpos, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; if (patch_long_forward_jump_instruction (moo, postcondpos, moo->c->mth.code.len, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops;
} }
if (cond_style == -1) if (cond_style == -1)
@ -4641,8 +4710,12 @@ static int compile_while_expression (moo_t* moo)
moo->c->mth.code.len = precondpos; moo->c->mth.code.len = precondpos;
} }
/* destroy the loop information stored earlier in this function */ /* patch the jump instructions for break */
pop_loop (moo, 1); if (update_loop_breaks (moo, moo->c->mth.code.len) <= -1) goto oops;
/* destroy the loop information stored earlier in this function */
pop_loop (moo);
loop_pushed = 0;
/* push nil as a result of the while expression. TODO: is it the best value? anything else? */ /* push nil as a result of the while expression. TODO: is it the best value? anything else? */
if (emit_byte_instruction (moo, BCODE_PUSH_NIL) <= -1) goto oops; if (emit_byte_instruction (moo, BCODE_PUSH_NIL) <= -1) goto oops;
@ -4650,7 +4723,117 @@ static int compile_while_expression (moo_t* moo)
return 0; return 0;
oops: oops:
if (loop_pushed) pop_loop (moo, 0); if (loop_pushed) pop_loop (moo);
return -1;
}
static int compile_do_while_expression (moo_t* moo)
{
moo_ioloc_t do_loc;
moo_oow_t precondpos, postcondpos, prebbpos, postbbpos;
int jbinst = 0, loop_pushed = 0;
moo_loop_t* loop = MOO_NULL;
MOO_ASSERT (moo, TOKEN_TYPE(moo) == MOO_IOTOK_DO);
do_loc = *TOKEN_LOC(moo);
GET_TOKEN (moo); /* get { */
prebbpos = moo->c->mth.code.len;
/* remember information about this loop.
* position of the conditional is not known yet.*/
if (push_loop (moo, MOO_LOOP_DO_WHILE, prebbpos) <= -1) goto oops;
loop_pushed = 1;
if (compile_braced_block(moo) <= -1) goto oops;
GET_TOKEN (moo); /* get the next token after } */
if (TOKEN_TYPE(moo) != MOO_IOTOK_WHILE)
{
set_syntax_error (moo, MOO_SYNERR_WHILE, TOKEN_LOC(moo), TOKEN_NAME(moo));
goto oops;
}
GET_TOKEN (moo); /* get ( */
postbbpos = moo->c->mth.code.len;
if (prebbpos + 1 == postbbpos && moo->c->mth.code.ptr[prebbpos] == BCODE_PUSH_NIL)
{
/* optimization -
* the braced block is kind of empty as it only pushes nil.
* get rid of this push instruction and don't generate the POP_STACKTOP */
moo->c->mth.code.len = prebbpos;
precondpos = prebbpos;
}
else if (prebbpos < postbbpos)
{
/* emit code to pop the value pushed by the braced block */
if (emit_byte_instruction (moo, BCODE_POP_STACKTOP) <= -1) goto oops;
}
precondpos = moo->c->mth.code.len;
/* update jump instructions emitted for continue */
if (update_loop_continues (moo, precondpos) <= -1) goto oops;
/* cannnot destroy the loop information because of pending jump updates
* for break. but need to unlink it as the conditional is not really
* part of the loop body */
loop = unlink_loop (moo);
if (compile_conditional (moo) <= -1) goto oops;
postcondpos = moo->c->mth.code.len;
jbinst = BCODE_JUMP_BACKWARD_IF_TRUE_0;
if (precondpos + 1 == postcondpos)
{
/* simple optimization -
* if the conditional is known to be true, emit the absolute jump instruction.
* if it is known to be false, kill all generated instructions. */
if (moo->c->mth.code.ptr[precondpos] == BCODE_PUSH_TRUE)
{
/* the conditional is always true. eliminate PUSH_TRUE and emit an absolute jump */
moo->c->mth.code.len = precondpos;
postcondpos = precondpos;
jbinst = BCODE_JUMP_BACKWARD_0;
}
else if (moo->c->mth.code.ptr[precondpos] == BCODE_PUSH_FALSE)
{
/* the conditional is always false. eliminate PUSH_FALSE and don't emit jump */
moo->c->mth.code.len = precondpos;
postcondpos = precondpos;
goto skip_emitting_jump_backward;
}
}
if (emit_backward_jump_instruction (moo, jbinst, moo->c->mth.code.len - prebbpos) <= -1)
{
if (moo->errnum == MOO_ERANGE)
{
/* the jump offset is out of the representable range by the offset
* portion of the jump instruction */
set_syntax_error (moo, MOO_SYNERR_BLKFLOOD, &do_loc, MOO_NULL);
}
goto oops;
}
skip_emitting_jump_backward:
GET_TOKEN (moo); /* get the next token after ) */
/* update jump instructions emitted for break */
if (update_loop_jumps (moo, &loop->break_ip_pool, moo->c->mth.code.len) <= -1) return -1;
free_loop (moo, loop);
loop = MOO_NULL;
loop_pushed = 0;
/* push nil as a result of the while expression. TODO: is it the best value? anything else? */
if (emit_byte_instruction (moo, BCODE_PUSH_NIL) <= -1) goto oops;
return 0;
oops:
if (loop_pushed)
{
if (loop) free_loop (moo, loop);
else pop_loop (moo);
}
return -1; return -1;
} }
@ -4677,6 +4860,10 @@ static int compile_method_expression (moo_t* moo, int pop)
{ {
if (compile_while_expression (moo) <= -1) return -1; if (compile_while_expression (moo) <= -1) return -1;
} }
else if (TOKEN_TYPE(moo) == MOO_IOTOK_DO)
{
if (compile_do_while_expression (moo) <= -1) return -1;
}
else if (TOKEN_TYPE(moo) == MOO_IOTOK_IDENT || else if (TOKEN_TYPE(moo) == MOO_IOTOK_IDENT ||
TOKEN_TYPE(moo) == MOO_IOTOK_IDENT_DOTTED) TOKEN_TYPE(moo) == MOO_IOTOK_IDENT_DOTTED)
{ {
@ -4838,10 +5025,13 @@ static int compile_special_statement (moo_t* moo)
} }
GET_TOKEN (moo); /* read the next token to continue */ GET_TOKEN (moo); /* read the next token to continue */
return emit_backward_jump_instruction (moo, moo->c->mth.code.len - moo->c->mth.loop->startpos);
return (moo->c->mth.loop->type == MOO_LOOP_DO_WHILE)?
inject_continue_to_loop (moo): /* in a do-while loop, the position to the conditional is not known yet */
emit_backward_jump_instruction (moo, BCODE_JUMP_BACKWARD_0, moo->c->mth.code.len - moo->c->mth.loop->startpos);
} }
return 9999; /* to indicate that no special stament has been seen and processed */ return 9999; /* to indicate that no special statement has been seen and processed */
} }
static int compile_block_statement (moo_t* moo) static int compile_block_statement (moo_t* moo)
@ -4858,7 +5048,6 @@ static int compile_block_statement (moo_t* moo)
static int compile_method_statement (moo_t* moo) static int compile_method_statement (moo_t* moo)
{ {
/* /*
* method-statement := method-return-statement | break | continue | method-expression * method-statement := method-return-statement | break | continue | method-expression
* method-return-statement := "^" method-expression * method-return-statement := "^" method-expression

View File

@ -280,6 +280,18 @@ int moo_decode (moo_t* moo, moo_oop_method_t mth, const moo_oocs_t* classfqn)
LOG_INST_1 (moo, "jump_backward_if_false %zu", (moo_oow_t)(bcode & 0x3)); /* low 2 bits */ LOG_INST_1 (moo, "jump_backward_if_false %zu", (moo_oow_t)(bcode & 0x3)); /* low 2 bits */
break; break;
case BCODE_JUMP_BACKWARD_IF_TRUE_X:
FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "jump_backward_if_true %zu", b1);
break;
case BCODE_JUMP_BACKWARD_IF_TRUE_0:
case BCODE_JUMP_BACKWARD_IF_TRUE_1:
case BCODE_JUMP_BACKWARD_IF_TRUE_2:
case BCODE_JUMP_BACKWARD_IF_TRUE_3:
LOG_INST_1 (moo, "jump_backward_if_true %zu", (moo_oow_t)(bcode & 0x3)); /* low 2 bits */
break;
case BCODE_JUMP2_FORWARD: case BCODE_JUMP2_FORWARD:
FETCH_PARAM_CODE_TO (moo, b1); FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "jump2_forward %zu", b1); LOG_INST_1 (moo, "jump2_forward %zu", b1);
@ -299,6 +311,11 @@ int moo_decode (moo_t* moo, moo_oop_method_t mth, const moo_oocs_t* classfqn)
FETCH_PARAM_CODE_TO (moo, b1); FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "jump2_backward_if_false %zu", b1); LOG_INST_1 (moo, "jump2_backward_if_false %zu", b1);
break; break;
case BCODE_JUMP2_BACKWARD_IF_TRUE:
FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "jump2_backward_if_true %zu", b1);
break;
/* -------------------------------------------------------- */ /* -------------------------------------------------------- */
case BCODE_PUSH_CTXTEMPVAR_X: case BCODE_PUSH_CTXTEMPVAR_X:

View File

@ -126,6 +126,7 @@ static moo_ooch_t synerrstr_54[] = {'d','u','p','l','i','c','a','t','e',' ','p',
static moo_ooch_t synerrstr_55[] = {'l','i','t','e','r','a','l',' ','e','x','p','e','c','t','e','d','\0'}; static moo_ooch_t synerrstr_55[] = {'l','i','t','e','r','a','l',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_56[] = {'b','r','e','a','k',' ','o','r',' ','c','o','n','t','i','n','u','e',' ','n','o','t',' ','w','i','t','h','i','n',' ','a',' ','l','o','o','p','\0'}; static moo_ooch_t synerrstr_56[] = {'b','r','e','a','k',' ','o','r',' ','c','o','n','t','i','n','u','e',' ','n','o','t',' ','w','i','t','h','i','n',' ','a',' ','l','o','o','p','\0'};
static moo_ooch_t synerrstr_57[] = {'b','r','e','a','k',' ','o','r',' ','c','o','n','t','i','n','u','e',' ','w','i','t','h','i','n',' ','a',' ','b','l','o','c','k','\0'}; static moo_ooch_t synerrstr_57[] = {'b','r','e','a','k',' ','o','r',' ','c','o','n','t','i','n','u','e',' ','w','i','t','h','i','n',' ','a',' ','b','l','o','c','k','\0'};
static moo_ooch_t synerrstr_58[] = {'w','h','i','l','e',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t* synerrstr[] = static moo_ooch_t* synerrstr[] =
{ {
synerrstr_0, synerrstr_1, synerrstr_2, synerrstr_3, synerrstr_4, synerrstr_5, synerrstr_6, synerrstr_7, synerrstr_0, synerrstr_1, synerrstr_2, synerrstr_3, synerrstr_4, synerrstr_5, synerrstr_6, synerrstr_7,
@ -135,7 +136,7 @@ static moo_ooch_t* synerrstr[] =
synerrstr_32, synerrstr_33, synerrstr_34, synerrstr_35, synerrstr_36, synerrstr_37, synerrstr_38, synerrstr_39, synerrstr_32, synerrstr_33, synerrstr_34, synerrstr_35, synerrstr_36, synerrstr_37, synerrstr_38, synerrstr_39,
synerrstr_40, synerrstr_41, synerrstr_42, synerrstr_43, synerrstr_44, synerrstr_45, synerrstr_46, synerrstr_47, synerrstr_40, synerrstr_41, synerrstr_42, synerrstr_43, synerrstr_44, synerrstr_45, synerrstr_46, synerrstr_47,
synerrstr_48, synerrstr_49, synerrstr_50, synerrstr_51, synerrstr_52, synerrstr_53, synerrstr_54, synerrstr_55, synerrstr_48, synerrstr_49, synerrstr_50, synerrstr_51, synerrstr_52, synerrstr_53, synerrstr_54, synerrstr_55,
synerrstr_56, synerrstr_57 synerrstr_56, synerrstr_57, synerrstr_58
}; };
#endif #endif
/* END: GENERATED WITH generr.st */ /* END: GENERATED WITH generr.st */

View File

@ -3515,6 +3515,22 @@ int moo_execute (moo_t* moo)
MOO_STACK_POP (moo); MOO_STACK_POP (moo);
break; break;
case BCODE_JUMP_BACKWARD_IF_TRUE_X:
FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "jump_backward_if_true %zu", b1);
if (MOO_STACK_GETTOP(moo) == moo->_true) moo->ip -= b1;
MOO_STACK_POP (moo);
break;
case BCODE_JUMP_BACKWARD_IF_TRUE_0:
case BCODE_JUMP_BACKWARD_IF_TRUE_1:
case BCODE_JUMP_BACKWARD_IF_TRUE_2:
case BCODE_JUMP_BACKWARD_IF_TRUE_3:
LOG_INST_1 (moo, "jump_backward_if_true %zu", (moo_oow_t)(bcode & 0x3));
if (MOO_STACK_GETTOP(moo) == moo->_true) moo->ip -= (bcode & 0x3); /* low 2 bits */
MOO_STACK_POP (moo);
break;
case BCODE_JUMP2_FORWARD: case BCODE_JUMP2_FORWARD:
FETCH_PARAM_CODE_TO (moo, b1); FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "jump2_forward %zu", b1); LOG_INST_1 (moo, "jump2_forward %zu", b1);
@ -3541,6 +3557,12 @@ int moo_execute (moo_t* moo)
MOO_STACK_POP (moo); MOO_STACK_POP (moo);
break; break;
case BCODE_JUMP2_BACKWARD_IF_TRUE:
FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "jump2_backward_if_true %zu", b1);
if (MOO_STACK_GETTOP(moo) == moo->_true) moo->ip -= MAX_CODE_JUMP + b1;
MOO_STACK_POP (moo);
break;
/* -------------------------------------------------------- */ /* -------------------------------------------------------- */
case BCODE_PUSH_CTXTEMPVAR_X: case BCODE_PUSH_CTXTEMPVAR_X:

View File

@ -334,6 +334,7 @@ struct moo_iotok_t
MOO_IOTOK_ELSIF, MOO_IOTOK_ELSIF,
MOO_IOTOK_WHILE, MOO_IOTOK_WHILE,
MOO_IOTOK_DO,
MOO_IOTOK_BREAK, MOO_IOTOK_BREAK,
MOO_IOTOK_CONTINUE MOO_IOTOK_CONTINUE
} type; } type;
@ -374,11 +375,20 @@ struct moo_oow_pool_t
moo_oow_t count; moo_oow_t count;
}; };
enum moo_loop_type_t
{
MOO_LOOP_WHILE,
MOO_LOOP_DO_WHILE
};
typedef enum moo_loop_type_t moo_loop_type_t;
typedef struct moo_loop_t moo_loop_t; typedef struct moo_loop_t moo_loop_t;
struct moo_loop_t struct moo_loop_t
{ {
moo_loop_type_t type;
moo_oow_t startpos; moo_oow_t startpos;
moo_oow_pool_t break_ip_pool; /* a pool that holds break instruction pointer */ moo_oow_pool_t break_ip_pool; /* a pool that holds jump instruction pointers for break */
moo_oow_pool_t continue_ip_pool; /* a pool that hold jump instructino pointers for continue. only for do-while */
moo_oow_t blkcount; /* number of inner blocks enclosed in square brackets */ moo_oow_t blkcount; /* number of inner blocks enclosed in square brackets */
moo_loop_t* next; moo_loop_t* next;
}; };
@ -611,10 +621,9 @@ SHORT INSTRUCTION CODE LONG INSTRUCTION C
68-71 0100 01XX JUMP_FORWARD 196 1100 0100 XXXXXXXX JUMP_FORWARD_X 68-71 0100 01XX JUMP_FORWARD 196 1100 0100 XXXXXXXX JUMP_FORWARD_X
72-75 0100 10XX JUMP_BACKWARD 200 1100 1000 XXXXXXXX JUMP_BACKWARD_X 72-75 0100 10XX JUMP_BACKWARD 200 1100 1000 XXXXXXXX JUMP_BACKWARD_X
76-79 0100 11XX JUMP_BACKWARD_IF_FALSE 204 1100 1100 XXXXXXXX JUMP_BACKWARD_IF_FALSE_X 76-79 0100 11XX JUMP_BACKWARD_IF_FALSE 204 1100 1100 XXXXXXXX JUMP_BACKWARD_IF_FALSE_X
80-83 0101 00XX JUMP_FORWARD_IF_FALSE 208 1101 0000 XXXXXXXX JUMP_FORWARD_IF_FALSE_X 80-83 0101 00XX JUMP_FORWARD_IF_FALSE 208 1101 0000 XXXXXXXX JUMP_FORWARD_IF_FALSE_X
84-87 0101 01XX JUMP_FORWARD_IF_TRUE 212 1101 0100 XXXXXXXX JUMP_FORWARD_IF_TRUE_X
84-87 0101 01XX UNUSED
vv vv
88-91 0101 10XX YYYYYYYY STORE_INTO_CTXTEMPVAR 216 1101 1000 XXXXXXXX YYYYYYYY STORE_INTO_CTXTEMPVAR_X (bit 3 on, bit 2 off) 88-91 0101 10XX YYYYYYYY STORE_INTO_CTXTEMPVAR 216 1101 1000 XXXXXXXX YYYYYYYY STORE_INTO_CTXTEMPVAR_X (bit 3 on, bit 2 off)
@ -750,6 +759,11 @@ enum moo_bcode_t
BCODE_JUMP_BACKWARD_IF_FALSE_2 = 0x52, /* 82 */ BCODE_JUMP_BACKWARD_IF_FALSE_2 = 0x52, /* 82 */
BCODE_JUMP_BACKWARD_IF_FALSE_3 = 0x53, /* 83 */ BCODE_JUMP_BACKWARD_IF_FALSE_3 = 0x53, /* 83 */
BCODE_JUMP_BACKWARD_IF_TRUE_0 = 0x54, /* 84 */
BCODE_JUMP_BACKWARD_IF_TRUE_1 = 0x55, /* 85 */
BCODE_JUMP_BACKWARD_IF_TRUE_2 = 0x56, /* 86 */
BCODE_JUMP_BACKWARD_IF_TRUE_3 = 0x57, /* 87 */
BCODE_STORE_INTO_CTXTEMPVAR_0 = 0x58, /* 88 */ BCODE_STORE_INTO_CTXTEMPVAR_0 = 0x58, /* 88 */
BCODE_STORE_INTO_CTXTEMPVAR_1 = 0x59, /* 89 */ BCODE_STORE_INTO_CTXTEMPVAR_1 = 0x59, /* 89 */
BCODE_STORE_INTO_CTXTEMPVAR_2 = 0x5A, /* 90 */ BCODE_STORE_INTO_CTXTEMPVAR_2 = 0x5A, /* 90 */
@ -832,6 +846,8 @@ enum moo_bcode_t
BCODE_JUMP2_FORWARD_IF_FALSE = 0xCD, /* 205 */ BCODE_JUMP2_FORWARD_IF_FALSE = 0xCD, /* 205 */
BCODE_JUMP_BACKWARD_IF_FALSE_X = 0xD0, /* 208 ## */ BCODE_JUMP_BACKWARD_IF_FALSE_X = 0xD0, /* 208 ## */
BCODE_JUMP2_BACKWARD_IF_FALSE = 0xD1, /* 209 */ BCODE_JUMP2_BACKWARD_IF_FALSE = 0xD1, /* 209 */
BCODE_JUMP_BACKWARD_IF_TRUE_X = 0xD4, /* 212 ## */
BCODE_JUMP2_BACKWARD_IF_TRUE = 0xD5, /* 213 */
BCODE_STORE_INTO_CTXTEMPVAR_X = 0xD8, /* 216 ## */ BCODE_STORE_INTO_CTXTEMPVAR_X = 0xD8, /* 216 ## */
BCODE_POP_INTO_CTXTEMPVAR_X = 0xDC, /* 220 ## */ BCODE_POP_INTO_CTXTEMPVAR_X = 0xDC, /* 220 ## */

View File

@ -1148,7 +1148,8 @@ enum moo_synerrnum_t
MOO_SYNERR_POOLDICDUP, /* duplicate pool dictionary */ MOO_SYNERR_POOLDICDUP, /* duplicate pool dictionary */
MOO_SYNERR_LITERAL, /* literal expected */ MOO_SYNERR_LITERAL, /* literal expected */
MOO_SYNERR_NOTINLOOP, /* break or continue not within a loop */ MOO_SYNERR_NOTINLOOP, /* break or continue not within a loop */
MOO_SYNERR_INBLOCK /* break or continue within a block */ MOO_SYNERR_INBLOCK, /* break or continue within a block */
MOO_SYNERR_WHILE /* while expected */
}; };
typedef enum moo_synerrnum_t moo_synerrnum_t; typedef enum moo_synerrnum_t moo_synerrnum_t;