📄 compiler.cpp
字号:
frequire ( T_IDENTIFIER );
package_name = class_name;
class_name = scan.t_token;
PACKAGE *pkg = get_package ( package_name, true );
klass = get_class ( class_name, pkg, true );
}
else
{
scan.stoken ( tkn );
klass = get_class ( class_name, 0, true );
}
code_literal ( this, package->add_literal ( VALUE ( klass ) ) );
pv->fcn = NULL;
int n = 1;
// generate code to push the selector
putcbyte ( OP_PUSH );
code_literal ( this,
package->add_literal (
VM::voc [ (const char *) class_name ] ) );
if ( ( tkn = scan.token () ) == '(' )
{
// compile the argument arglist
if ( ( tkn = scan.token () ) != ')' )
{
scan.stoken ( tkn );
do
{
putcbyte ( OP_PUSH );
do_expr2 ( pv );
rvalue ( pv );
++n;
}
while ( ( tkn = scan.token () ) == ',' );
}
require ( tkn, ')' );
}
else
scan.stoken ( tkn );
// send the message
putcbyte ( OP_NEW );
putcbyte ( n );
// we've got an rvalue now
pv->fcn = NULL;
}
// do_expr15 - handle function calls
void
compiler::do_expr15 ( compiler::PVAL *pv )
{
string selector;
int tkn;
do_primary ( pv );
while ( ( tkn = scan.token () ) == '(' ||
tkn == '[' || tkn == T_MEMREF ||
tkn == T_INC || tkn == T_DEC )
switch ( tkn )
{
case '(':
do_call ( pv );
break;
case '[':
do_index ( pv );
break;
case T_MEMREF:
frequire ( T_IDENTIFIER );
selector = scan.t_token;
do_memref ( selector, pv );
break;
case T_INC:
do_postincrement ( pv, OP_INC );
break;
case T_DEC:
do_postincrement ( pv, OP_DEC );
break;
}
scan.stoken ( tkn );
}
// do_primary - parse a primary expression and unary operators
void
compiler::do_primary ( compiler::PVAL *pv )
{
CLASS *klass;
int tkn;
switch ( scan.token () )
{
case '(':
do_expr1 ( pv );
frequire ( ')' );
break;
case T_NUMBER:
do_lit_number ( scan.t_value );
pv->fcn = NULL;
break;
case T_STRING:
do_lit_string ( scan.t_token );
pv->fcn = NULL;
break;
case T_NULL:
putcbyte ( OP_NULL );
pv->fcn = NULL;
break;
case T_UNDEFINED:
putcbyte ( OP_UNDEFINED );
pv->fcn = NULL;
break;
case T_ARGUMENTS:
putcbyte ( OP_ARGUMENTS );
pv->fcn = NULL;
break;
case T_ARGUMENT:
do_expr2 ( pv );
rvalue ( pv );
putcbyte ( OP_ARGUMENT );
pv->fcn = NULL;
break;
case '[':
do_lit_array ( pv );
break;
case '{':
do_lit_map ( pv );
break;
case T_IDENTIFIER:
{
string member_id = scan.t_token;
if ( ( tkn = scan.token () ) == T_CC )
{
frequire ( T_IDENTIFIER );
string package_id;
string class_id = member_id;
member_id = scan.t_token;
if ( ( tkn = scan.token () ) == T_CC )
{
frequire ( T_IDENTIFIER );
package_id = class_id;
class_id = member_id;
member_id = scan.t_token;
}
else
{
scan.stoken ( tkn );
}
klass = get_class_or_package ( class_id, package_id );
assert ( klass );
if ( ! findclassvariable ( klass, (const char *) member_id, pv ) )
throw parse_error ( this, "'%s' is not a member of class '%s'",
(const char *) member_id,
(const char *) klass->full_name () );
}
else
{
scan.stoken ( tkn );
findvariable ( (const char *) member_id, pv );
}
}
break;
default:
throw parse_error ( this, "Expecting a primary expression" );
break;
}
}
// do_call - compile a function call
void
compiler::do_call ( compiler::PVAL *pv )
{
int tkn, n = 1;
// get the value of the function
rvalue ( pv );
// put <undefined> as this
putcbyte ( OP_PUSH );
// compile each argument expression
if ( ( tkn = scan.token () ) != ')' )
{
scan.stoken ( tkn );
do
{
putcbyte ( OP_PUSH );
do_expr2 ( pv );
rvalue ( pv );
if ( ++n >= 10000 )
throw parse_error ( this, "Too many parameters" );
}
while ( ( tkn = scan.token () ) == ',' );
}
require ( tkn, ')' );
putcbyte ( OP_CALL );
putcword ( n );
// we've got an rvalue now
pv->fcn = NULL;
}
// do_send - compile a message sending expression
void
compiler::do_memref ( const char *selector, compiler::PVAL *pv )
{
// get the receiver value
rvalue ( pv );
// generate code to push the selector
putcbyte ( OP_PUSH );
code_literal ( this, package->add_literal ( VM::voc [ selector ] ) );
pv->fcn = code_prop_member;
}
// do_index - compile an indexing operation
void
compiler::do_index ( compiler::PVAL *pv )
{
rvalue ( pv );
putcbyte ( OP_PUSH );
do_expr ();
frequire ( ']' );
pv->fcn = code_index;
}
// get_id_list - get a comma separated arglist of identifiers
int
compiler::get_id_list ( sym_table& st, const char *term )
{
int tkn, cnt = 0; symbol_t t;
tkn = scan.token ();
if ( ! strchr ( term, tkn ) )
{
scan.stoken ( tkn );
do
{
frequire ( T_IDENTIFIER );
if ( st.find ( scan.t_token, t ) )
{
char buf [ 100 ];
sprintf ( buf, "'%s' already defined.",
(const char *) scan.t_token );
throw parse_error ( this, buf );
}
else
(void) st [ scan.t_token ];
}
while ( ( tkn = scan.token () ) == ',' );
}
scan.stoken ( tkn );
return st.size ();
}
// findarg - find an argument offset
int
compiler::findarg ( const char *name )
{
symbol_t t;
return arguments.find ( name, t ) ? (int) t : -1;
}
// findtmp - find a temporary variable offset
int
compiler::findtmp ( const char *name )
{
if ( temporaries == 0 )
return -1;
return (int) temporaries->find ( name );
}
// finddatamember - find a klass data member
ENTRY
compiler::finddatamember ( const char *name )
{
CLASS *klass = methodclass;
if ( klass )
{
do
{
ENTRY e = klass->find ( name );
if ( e.is_valid () )
return e;
klass = klass->base;
}
while ( klass );
}
return ENTRY::undefined ();
}
// frequire - fetch a token and check it
void
compiler::frequire ( int rtkn )
{
require ( scan.token (), rtkn );
}
// require - check for a required token
void
compiler::require ( int tkn, int rtkn )
{
char msg [ 100 ], tknbuf [ 100 ];
if ( tkn != rtkn )
{
strncpy ( tknbuf, scan.tkn_name ( rtkn ), 100 );
snprintf ( msg, 100, "Expecting '%s', found '%s'", tknbuf, scan.tkn_name ( tkn ) );
throw parse_error ( this, msg );
}
}
// do_lit_integer - compile a literal number
void
compiler::do_lit_number ( VALUE v )
{
code_literal ( this, package->add_literal ( v ) );
}
// do_lit_string - compile a literal string
void
compiler::do_lit_string ( const char *str )
{
code_literal ( this, package->add_literal ( str ) );
}
// make_lit_symbol - make a literal string
int
compiler::make_lit_symbol ( const char *str )
{
return package->add_literal ( VM::voc [ str ] );
}
// make_lit_string - make a literal string
int
compiler::make_lit_string ( const char *str )
{
return package->add_literal ( str );
}
// make_lit_variable - make a literal reference to a variable
int
compiler::make_lit_variable ( ENTRY e )
{
return package->add_literal ( VALUE ( e ) );
}
// findvariable - find a variable
void
compiler::findvariable ( const char *id, compiler::PVAL *pv )
{
int n;
if ( ( n = findarg ( id ) ) >= 0 )
{
pv->fcn = code_argument;
pv->val = n;
}
else if ( ( n = findtmp ( id ) ) >= 0 )
{
pv->fcn = code_temporary;
pv->val = n;
}
else if ( methodclass && findclassvariable ( methodclass, id, pv ) )
{
;
}
else if ( findclassvariable ( package, id, pv ) )
{
;
}
else if ( findclassvariable ( VM::std, id, pv ) )
{
;
}
else
throw parse_error ( this, "Variable or method '%s' not found", id );
}
// findclassvariable - find a klass member variable
int
compiler::findclassvariable ( CLASS *klass, const char *name,
compiler::PVAL *pv )
{
ENTRY e = rfindmember ( klass, name );
if ( !e.is_valid () )
return false;
switch ( e.type () )
{
case ST_DATA:
pv->fcn = code_member;
pv->val = e.value()->v.v_integer;
break;
case ST_SDATA:
pv->fcn = code_variable;
pv->val = make_lit_variable ( e );
break;
case ST_CONST:
pv->fcn = code_const;
pv->val = make_lit_variable ( e );
break;
case ST_FUNCTION:
if ( findarg ( "this" ) >= 0 )
{
findvariable ( "this", pv );
do_memref ( name, pv );
break;
}
case ST_SFUNCTION:
code_variable ( this, LOAD, make_lit_variable ( e ) );
pv->fcn = NULL;
break;
}
return true;
}
// code_argument - compile an argument reference
void
compiler::code_argument ( compiler *c, int fcn, int n )
{
switch ( fcn )
{
case LOAD: c->putcbyte ( OP_AREF ); c->putcbyte ( n ); break;
case STORE: c->putcbyte ( OP_ASET ); c->putcbyte ( n ); break;
}
}
// code_temporary - compile a temporary variable reference
void
compiler::code_temporary ( compiler *c, int fcn, int n )
{
switch ( fcn )
{
case LOAD: c->putcbyte ( OP_TREF ); c->putcbyte ( n ); break;
case STORE: c->putcbyte ( OP_TSET ); c->putcbyte ( n ); break;
}
}
// code_member - compile a data member reference
void
compiler::code_member ( compiler *c, int fcn, int n )
{
switch ( fcn )
{
case LOAD: c->putcbyte ( OP_MREF ); c->putcbyte ( n ); break;
case STORE: c->putcbyte ( OP_MSET ); c->putcbyte ( n ); break;
}
}
// code_variable - compile a variable reference
void
compiler::code_variable ( compiler *c, int fcn, int n )
{
switch ( fcn )
{
case LOAD: c->putcbyte ( OP_REF ); c->putcword ( n ); break;
case STORE: c->putcbyte ( OP_SET ); c->putcword ( n ); break;
}
}
// code_variable - compile a variable reference
void
compiler::code_const ( compiler *c, int fcn, int n )
{
switch ( fcn )
{
case LOAD: c->putcbyte ( OP_REF ); c->putcword ( n ); break;
case STORE: throw parse_error ( c, "attempt to change constant" );
}
}
// code_index - compile an indexed reference
void
compiler::code_index ( compiler *c, int fcn, int n )
{
switch ( fcn )
{
case LOAD: c->putcbyte ( OP_VREF ); break;
case STORE: c->putcbyte ( OP_VSET ); break;
case PUSH: c->putcbyte ( OP_PUSH ); break;
case DUP: c->putcbyte ( OP_DUP2 ); break;
}
}
// code_prop_member - compile an object property reference
void
compiler::code_prop_member ( compiler *c, int fcn, int n )
{
switch ( fcn )
{
case LOAD: c->putcbyte ( OP_PMREF ); break;
case STORE: c->putcbyte ( OP_PMSET ); break;
case PUSH: c->putcbyte ( OP_PUSH ); break;
case DUP: c->putcbyte ( OP_DUP2 ); break;
}
}
// code_literal - compile a literal reference
void
compiler::code_literal ( compiler *c, int n )
{
c->putcbyte ( OP_LIT );
c->putcword ( n );
}
// putcbyte - put a code byte into data space
int
compiler::putcbyte ( int b )
{
if ( file_line != scan.lnum )
{
file_line = scan.lnum;
_putcbyte ( OP_LINE );
putcword ( file_line );
}
return _putcbyte ( b );
}
// putcbyte - put a code byte into data space
int
compiler::_putcbyte ( int b )
{
if ( cptr >= CMAX )
throw parse_error ( this, "Insufficient code space" );
cbuff [ cptr ] = b;
return ( cptr++ );
}
// putcword - put a code word into data space
int
compiler::putcword ( int w )
{
_putcbyte ( w );
_putcbyte ( w >> 8 );
return ( cptr - 2 );
}
// fixup - fixup a reference chain
void
compiler::fixup ( int chn, int val )
{
int hval, nxt;
for ( hval = val >> 8; chn != 0; chn = nxt )
{
nxt = ( cbuff [ chn ] & 0xFF ) | ( cbuff [ chn + 1 ] << 8 );
cbuff [ chn ] = val;
cbuff [ chn + 1 ] = hval;
}
}
#endif //COMPILER
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -