📄 compiler.cpp
字号:
}
putcbyte ( OP_RETURN );
}
// update OP_TSPACE operand
tcnt = temporaries->get_total ();
cbuff [ c_tspace ] = tcnt;
delete temporaries; // unwind all stack please;
temporaries = 0;
BUFFER *bc = new BUFFER ( cptr );
// build the function
CODE *bytecode = new CODE ( VM::voc [ name ], bc, klass );
// create the code string
unsigned char *src = cbuff, *dst = &( *bc ) [ 0 ];
while ( --cptr >= 0 )
*dst++ = *src++;
#ifdef DECODE_TRACE
// show the generated code
VM::decode_procedure ( bytecode );
#endif
//restore
cbuff = old_cbuff; // code buffer
cptr = old_cptr; // code pointer
arguments.clear ();
if ( klass )
klass->check_name ( VM::voc [ name ], bytecode, stype );
// return the code object
return bytecode;
}
// do_init_code - compile the code part of a package
void
compiler::do_static_vardecl ( CLASS *klass_or_package, bool constant )
{
int tkn;
string id;
compiler::PVAL rhs;
for ( ; ; )
{
tkn = scan.token ();
if ( tkn != T_IDENTIFIER )
throw parse_error ( this, "Expecting an identifier" );
id = scan.t_token;
//code_variable
ENTRY entry = klass_or_package->add ( id, constant ? ST_CONST
: ST_SDATA );
if ( !entry.is_valid () )
{
throw parse_error ( this, "Variable or constant '%s' already defined",
(const char *) id );
}
int lit_num = package->add_literal ( VALUE ( entry ) );
tkn = scan.token ();
if ( tkn == '=' )
{
code_variable ( this, PUSH, 0 );
do_expr2 ( &rhs );
rvalue ( &rhs );
code_variable ( this, STORE, lit_num );
tkn = scan.token ();
}
else
{
putcbyte ( OP_UNDEFINED );
code_variable ( this, STORE, lit_num );
}
if ( tkn == ',' )
continue;
else if ( tkn == ';' )
{
break;
}
else
throw parse_error ( this, "Expecting ',' | ';'" );
}
}
// get_class - get the klass associated with a symbol
CLASS *
compiler::get_class ( const char *name, PACKAGE *pkg, bool reportError )
{
if ( pkg == 0 )
{
CLASS * cls = get_class ( name, package );
if ( cls )
return cls;
cls = get_class ( name, VM::std );
if ( cls )
return cls;
throw parse_error ( this, "'%s' is not a class name", name );
}
ENTRY e = pkg->find ( name );
if ( e.is_valid () )
{
VALUE * v = e.value ();
if ( v && v->v_type == DT_CLASS )
return v->v.v_class;
}
if ( reportError )
throw parse_error ( this, "'%s' is not a class name", name );
return 0;
}
// get_class - get the klass associated with a symbol
PACKAGE *
compiler::get_package ( const char *name, bool reportError )
{
if ( package->name == VM::voc [ name ] )
return package;
int idx = VM::packages->find ( VM::voc [ name ] );
if ( idx < 0 )
{
if ( reportError )
throw parse_error ( this, "'%s' is not a package name", name );
return 0;
}
return (PACKAGE *) ( *( VM::packages ) ) [ idx ].value.v.v_class;
}
CLASS *
compiler::get_class_or_package ( string& class_id, string& package_id )
{
PACKAGE *pkg;
if ( package_id.length () )
{
pkg = get_package ( (const char *) package_id, true );
return get_class ( (const char *) class_id, pkg );
}
// first try to test is class_id is a package name
pkg = get_package ( (const char *) class_id, false );
if ( pkg )
return pkg;
return get_class ( (const char *) class_id );
}
// do_statement - compile a single statement
int
compiler::do_statement ()
{
int tkn;
switch ( tkn = scan.token () )
{
case T_IF: do_if (); return tkn;
case T_WHILE: do_while (); return tkn;
case T_DO: do_dowhile (); return tkn;
case T_FOR: do_for (); return tkn;
case T_BREAK: do_break (); frequire ( ';' ); return tkn;
case T_CONTINUE: do_continue (); frequire ( ';' ); return tkn;
case T_RETURN: do_return (); return tkn;
case T_TRY: do_try (); return tkn;
case T_THROW: do_throw (); return tkn;
case T_SYNCHRO: do_synchro (); return tkn;
case T_SWITCH: do_switch (); return tkn;
case '{': do_block (); break;
case ';': ; return tkn;
case T_VAR: do_vardecl (); break;
default:
scan.stoken ( tkn );
do_expr ();
frequire ( ';' );
break;
}
return 0;
}
// do_if - compile the IF/ELSE expression
void
compiler::do_if ()
{
int tkn, nxt, end;
// compile the test expression
do_test ();
// skip around the 'then' clause if the expression is false
putcbyte ( OP_BRF );
nxt = putcword ( 0 );
// compile the 'then' clause
do_statement ();
// compile the 'else' clause
if ( ( tkn = scan.token () ) == T_ELSE )
{
putcbyte ( OP_BR );
end = putcword ( 0 );
fixup ( nxt, cptr );
do_statement ();
nxt = end;
}
else
scan.stoken ( tkn );
// handle the end of the statement
fixup ( nxt, cptr );
}
void
compiler::do_switch ()
{
compiler::PVAL pv;
int nxt = 0, nxtbody = 0, end = 0, dflt = 0;
int *old_break;
frequire ( '(' );
do_expr1 ( &pv );
rvalue ( &pv );
frequire ( ')' );
frequire ( '{' );
old_break = addbreak ( 0 );
putcbyte ( OP_PUSH );
int tkn; int last_stm = 0;
while ( (tkn = scan.token () ) != T_EOF )
{
if ( tkn == '}' )
break;
if ( tkn == T_CASE )
{
if ( nxt )
{
if ( last_stm != T_BREAK && last_stm != T_RETURN )
{
putcbyte ( OP_BR );
nxtbody = putcword ( 0 );
}
fixup ( nxt, cptr );
}
else
nxtbody = 0;
putcbyte ( OP_COPY );
putcbyte ( OP_PUSH );
do_primary ( &pv );
rvalue ( &pv );
frequire ( ':' );
putcbyte ( OP_EQ );
putcbyte ( OP_BRF );
nxt = putcword ( 0 );
if ( nxtbody )
{
fixup ( nxtbody, cptr );
nxtbody = 0;
}
}
else if ( tkn == T_DEFAULT )
{
frequire ( ':' );
if ( nxt == 0 )
{
putcbyte ( OP_BR );
nxt = putcword ( 0 );
}
dflt = cptr;
}
else
{
if ( nxt == 0 )
throw parse_error ( this, "Expecting 'case' | 'default'" );
scan.stoken ( tkn );
int ls = do_statement ();
if ( ls != ';')
last_stm = ls;
}
}
end = rembreak ( old_break, end );
if ( nxt )
{
if ( dflt )
fixup ( nxt, dflt );
else
fixup ( nxt, cptr );
}
// handle the end of the statement
fixup ( end, cptr );
putcbyte ( OP_POP );
}
void
compiler::do_try ()
{
int nxt, end;
frequire ( '{' );
putcbyte ( OP_EH_PUSH );
nxt = putcword ( 0 );
do_block ();
putcbyte ( OP_EH_POP );
end = putcword ( 0 );
fixup ( nxt, cptr );
frequire ( T_CATCH );
frequire ( '(' );
frequire ( T_IDENTIFIER );
string ev = scan.t_token;
frequire ( ')' );
frequire ( '{' );
do_block ( ev );
// handle the end of the statement
fixup ( end, cptr );
}
void
compiler::do_throw ()
{
do_expr ();
frequire ( ';' );
putcbyte ( OP_THROW );
}
void
compiler::do_synchro ()
{
compiler::PVAL pv;
do_primary ( &pv );
rvalue ( &pv );
frequire ( '{' );
putcbyte ( OP_ENTER );
do_block ();
putcbyte ( OP_LEAVE );
}
// addbreak - add a break level to the stack
int *
compiler::addbreak ( int lbl )
{
int *old = bsp;
if ( ++bsp < &bstack [ SSIZE ] )
*bsp = lbl;
else
throw parse_error ( this, "Too many nested loops" );
return ( old );
}
// rembreak - remove a break level from the stack
int
compiler::rembreak ( int *old, int lbl )
{
return ( bsp > old ? *bsp-- : lbl );
}
// addcontinue - add a continue level to the stack
int *
compiler::addcontinue ( int lbl )
{
int *old = csp;
if ( ++csp < &cstack [ SSIZE ] )
*csp = lbl;
else
throw parse_error ( this, "Too many nested loops" );
return ( old );
}
// remcontinue - remove a continue level from the stack
void
compiler::remcontinue ( int *old )
{
csp = old;
}
// do_while - compile the WHILE expression
void
compiler::do_while ()
{
int nxt, end, *ob, *oc;
// compile the test expression
nxt = cptr;
do_test ();
// skip around the loop body if the expression is false
putcbyte ( OP_BRF );
end = putcword ( 0 );
// compile the loop body
ob = addbreak ( end );
oc = addcontinue ( nxt );
do_statement ();
end = rembreak ( ob, end );
remcontinue ( oc );
// branch back to the start of the loop
putcbyte ( OP_BR );
putcword ( nxt );
// handle the end of the statement
fixup ( end, cptr );
}
// do_dowhile - compile the DO/WHILE expression
void
compiler::do_dowhile ()
{
int nxt, end = 0, *ob, *oc;
// remember the start of the loop
nxt = cptr;
// compile the loop body
ob = addbreak ( 0 );
oc = addcontinue ( nxt );
do_statement ();
end = rembreak ( ob, end );
remcontinue ( oc );
// compile the test expression
frequire ( T_WHILE );
do_test ();
frequire ( ';' );
// branch to the top if the expression is true
putcbyte ( OP_BRT );
putcword ( nxt );
// handle the end of the statement
fixup ( end, cptr );
}
// do_for - compile the FOR statement
void
compiler::do_for ()
{
int tkn, nxt, end, body, update, *ob, *oc;
// compile the initialization expression
frequire ( '(' );
if ( (tkn = scan.token () ) != ';' )
{
if ( tkn == T_VAR )
do_vardecl ();
else
{
scan.stoken ( tkn );
do_expr ();
}
frequire ( ';' );
}
// compile the test expression
nxt = cptr;
if ( ( tkn = scan.token () ) != ';' )
{
scan.stoken ( tkn );
do_expr ();
frequire ( ';' );
}
// branch to the loop body if the expression is true
putcbyte ( OP_BRT );
body = putcword ( 0 );
// branch to the end if the expression is false
putcbyte ( OP_BR );
end = putcword ( 0 );
// compile the update expression
update = cptr;
if ( ( tkn = scan.token () ) != ')' )
{
scan.stoken ( tkn );
do_expr ();
frequire ( ')' );
}
// branch back to the test code
putcbyte ( OP_BR );
putcword ( nxt );
// compile the loop body
fixup ( body, cptr );
ob = addbreak ( end );
oc = addcontinue ( update );
do_statement ();
end = rembreak ( ob, end );
remcontinue ( oc );
// branch back to the update code
putcbyte ( OP_BR );
putcword ( update );
// handle the end of the statement
fixup ( end, cptr );
}
// do_break - compile the BREAK statement
void
compiler::do_break ()
{
if ( bsp >= bstack )
{
putcbyte ( OP_BR );
*bsp = putcword ( *bsp );
}
else
throw parse_error ( this, "Break outside of loop" );
}
// do_continue - compile the CONTINUE statement
void
compiler::do_continue ()
{
if ( csp >= cstack )
{
putcbyte ( OP_BR );
putcword ( *csp );
}
else
throw parse_error ( this, "Continue outside of loop" );
}
// do_block - compile the {} expression
int
compiler::do_block ( const char *parameter )
{
name_space *save_temp = temporaries;
temporaries = new name_space ( temporaries );
if ( parameter )
{
int temp_var_index = temporaries->add ( parameter );
code_temporary ( this, STORE, temp_var_index );
}
int tkn;
int last_stat = 0;
if ( (tkn = scan.token () ) != '}' )
{
do
{
scan.stoken ( tkn );
last_stat = do_statement ();
}
while ( (tkn = scan.token () ) != '}' );
}
else
putcbyte ( OP_UNDEFINED );
if ( save_temp )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -