📄 compiler.cpp
字号:
/*
*
* compiler.cpp
*
* Copyright (c) 2001, 2002
* Andrew Fedoniouk - andrew@terra-informatica.org
* Portions: Serge Kuznetsov - kuznetsov@deeptown.org
*
* See the file "COPYING" for information on usage
* and redistribution of this file
*
*/
#include <setjmp.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include "c-smile.h"
#include "compiler.h"
#include "streams.h"
#ifdef _WIN32
#define snprintf _snprintf
#endif
namespace c_smile
{
#ifdef COMPILER
// variable access function codes
#define LOAD 1
#define STORE 2
#define PUSH 3
#define DUP 4
compiler::compiler () : temporaries ( 0 ), methodclass ( 0 ), report_stream ( 0 )
{
}
// mark_compiler - mark compiler variables
void
compiler::mark ()
{
mark_thing ( methodclass );
mark_thing ( package );
temp.mark ();
}
void
compiler::report ( const char * format, ... )
{
if ( report_stream == 0 )
return;
}
// compile_definitions - compile klass or function definitions
PACKAGE *
compiler::compile ( io_stream *input )
{
file_name = input->name ();
int idx = max ( file_name.last_index_of ( '/' ),
file_name.last_index_of ( '\\' ) );
assert ( idx > 0 );
dir_name = file_name.substr ( 0, idx );
int tkn;
package = new PACKAGE ( 0, (const char *) file_name );
unsigned char stack_buff [ CMAX ];
cbuff = stack_buff;
cptr = 0;
inConstructor = false;
bool package_reported = false;
putcbyte ( OP_PUSH );
// trap errors
try
{
// initialize
scan.init ( this, input );
bsp = &bstack [ -1 ];
csp = &cstack [ -1 ];
// process statements until end of file
while ( (tkn = scan.token () ) != T_EOF )
{
switch ( tkn )
{
case T_PACKAGE:
do_package ();
if ( VM::packages->find ( package->name ) >= 0 )
{
delete package;
throw parse_error ( this, "Package '%s' already defined.",
VM::voc [ package->name ] );
}
break;
case T_IMPORT:
if ( package->name == 0 )
throw parse_error ( this, "Expecting package declaration" );
do_import ();
break;
default:
scan.stoken ( tkn );
goto stage1;
}
}
stage1:
report ( "package '%s'\n", VM::voc [ package->name ] );
VM::info ( "compiling '%s' ... ", VM::voc [ package->name ] );
// process statements until end of file
while ( ( tkn = scan.token () ) != T_EOF )
{
switch ( tkn )
{
case T_STATIC:
tkn = scan.token ();
if ( tkn == T_VAR )
{
do_static_vardecl ( (CLASS *) package, false );
break;
}
else if ( tkn != T_FUNCTION )
throw parse_error ( this, "Expecting 'var' | 'function'" );
// otherwise function
case T_FUNCTION:
do_function ();
break;
case T_CONST:
do_static_vardecl ( (CLASS *) package, true );
break;
case T_VAR:
do_static_vardecl ( (CLASS *) package, false );
break;
case T_CLASS:
do_class ();
break;
default:
throw parse_error ( this,
"Expecting function | class | var declaration" );
break;
}
}
putcbyte ( OP_RETURN );
BUFFER *bc = new BUFFER ( cptr );
// build the package init code
package->init_code = new CODE ( VM::voc [ "<init>" ],
bc, ( CLASS*) package );
// create the code string
unsigned char *src = cbuff, *dst = &( *bc ) [ 0 ];
while ( --cptr >= 0 )
*dst++ = *src++;
#ifdef DECODE_TRACE
// show the generated code
if ( VM::decode )
VM::decode_procedure ( package->init_code );
#endif
report ( "package '%s' done", VM::voc [ package->name ] );
VM::info ( "done.\n" );
}
catch ( parse_error& pe )
{
while ( temporaries )
{
name_space *t = temporaries;
temporaries = temporaries->parent;
}
delete package;
package = 0;
throw pe;
}
return package;
}
void
compiler::do_package ()
{
// get the package name
frequire ( T_IDENTIFIER );
if ( package->name != undefined_symbol )
throw parse_error ( this, "package already defined" );
package->name = VM::voc [ scan.t_token ];
frequire ( ';' );
}
void
compiler::do_import ()
{
// get the package name
while ( true )
{
frequire ( T_IDENTIFIER );
string package_name = scan.t_token;
PACKAGE *ipackage =
VM::find_package ( VM::voc [ (const char *) package_name ],
dir_name );
int tkn = scan.token ();
if ( tkn == ';' )
break;
if ( tkn != ',' )
throw parse_error ( this, "Expecting ',' | ';'" );
}
}
// do_class - handle class declarations
void
compiler::do_class ()
{
string cname;
int type, tkn;
// get the klass name
frequire ( T_IDENTIFIER );
cname = scan.t_token;
VALUE tv;
CLASS *cl = 0;
// get the optional base klass
if ( ( tkn = scan.token () ) == ':' )
{
frequire ( T_IDENTIFIER );
string cls_name = scan.t_token;
PACKAGE * pkg = 0;
if ( ( tkn = scan.token () ) == T_CC )
{
pkg = get_package ( cls_name, true );
frequire ( T_IDENTIFIER );
cls_name = scan.t_token;
}
else
scan.stoken ( tkn );
tv = get_class ( cls_name, pkg );
cl = tv.v.v_class;
report ( "\tclass '%s' base class '%s'",(const char *) cname,
VM::voc [ cl->name ] );
}
else
{
scan.stoken ( tkn );
report ( "\tclass '%s'", (const char *) cname );
}
frequire ( '{' );
// create the new class object
tv = cl = new CLASS ( cname, cl, package );
cl->instance_size = ( cl->base ) ? cl->base->instance_size : 0;
// handle each variable declaration
while ( ( tkn = scan.token () ) != '}' )
{
// check for members
int var = 0;
type = 0;
if ( tkn == T_STATIC )
{
type = T_STATIC;
var = T_VAR;
tkn = scan.token ();
}
if ( tkn == T_VAR )
{
var = T_VAR;
}
else if ( tkn == T_CONST )
{
type = T_STATIC;
var = T_CONST;
}
else if ( tkn == T_FUNCTION )
{
var = T_FUNCTION;
}
else if ( tkn == T_PROPERTY )
{
var = T_PROPERTY;
}
if ( var == 0 )
throw parse_error ( this,
"Expecting 'static' | 'const' | ['var' | 'function' | 'property' ]" );
// check for a member function declaration
if ( var == T_FUNCTION )
do_member_function ( cl, type );
// check for a member function declaration
else if ( var == T_PROPERTY )
do_property_function ( cl, type );
// handle data members
else if ( var == T_VAR )
{
if ( type == T_STATIC )
do_static_vardecl ( cl, false );
else
do_member_data ( cl, type );
}
else if ( var == T_CONST )
{
do_static_vardecl ( cl, true );
}
}
}
// do_member_data - parse a member data declarations
// token - clause token
void
compiler::do_member_data ( CLASS *klass, int token )
{
int tkn;
do
{
frequire ( T_IDENTIFIER );
ENTRY en = klass->add ( scan.t_token, ST_DATA );
if ( !en.is_valid () )
throw parse_error ( this, "Variable '%s' already defined.",
(const char *) scan.t_token );
VALUE *v = en.value ();
*v = klass->instance_size++;
}
while ( ( tkn = scan.token () ) == ',' );
scan.stoken ( tkn );
frequire ( ';' );
}
// do_member_function - parse a member function definition
void
compiler::do_member_function ( CLASS *klass, int type )
{
int tkn = scan.token ();
string selector;
if ( tkn == '[' )
{
if ( ( tkn = scan.token () ) != ']' )
throw parse_error ( this, "Expecting ]" );
selector = "[]";
}
else if ( tkn == T_IDENTIFIER )
{
selector = scan.t_token;
}
else
throw parse_error ( this, "Expecting identifier | [] | delete" );
const char * class_name = VM::voc [ klass->name ];
report ( "\t\tfunction '%s::%s'", class_name, (const char *) selector );
tkn = scan.token ();
if ( tkn != '(' )
throw parse_error ( this, "Expecting '('" );
int stype = type == T_STATIC ? ST_SFUNCTION : ST_FUNCTION;
bool musthavebody = false;
ENTRY e = klass->find ( selector );
if ( e.is_valid () )
{
if ( e.value()->is_null() )
throw parse_error ( this, "'%s::%s' already defined.", class_name,
(const char *) selector );
if ( e.type () != stype )
throw parse_error ( this,
"'%s::%s' previously defined having different type.",
class_name, (const char *) selector );
musthavebody = true;
}
else
{
e = klass->add ( selector, stype );
}
if ( stype == ST_FUNCTION )
inConstructor = ( klass->name == VM::voc [ selector ] );
VALUE *v = e.value ();
*v = do_code ( selector, klass, stype );
inConstructor = false;
}
// do_property_function - parse a member property function definition
void
compiler::do_property_function ( CLASS *klass, int type )
{
int tkn = scan.token ();
if ( tkn != T_IDENTIFIER )
throw parse_error ( this, "Expecting identifier" );
string selector = scan.t_token;
const char * class_name = VM::voc [ klass->name ];
report ( "\t\tproperty '%s::%s'", class_name, ( const char * ) selector );
tkn = scan.token ();
if ( tkn != '(' )
throw parse_error ( this, "Expecting '('" );
int stype = type == T_STATIC ? ST_SPROPERTY : ST_PROPERTY;
ENTRY e = klass->add ( selector, stype );
if ( !e.is_valid () )
throw parse_error ( this, "'%s::%s' already defined.", class_name,
(const char *) selector );
VALUE *v = e.value ();
*v = do_code ( selector, klass, stype );
}
// findmember - find a klass member
ENTRY
compiler::findmember ( CLASS *klass, const char *name )
{
return klass->find ( name );
}
// rfindmember - recursive findmember
ENTRY
compiler::rfindmember ( CLASS *klass, const char *name )
{
ENTRY e;
while ( klass )
{
e = klass->find ( name );
if ( e.is_valid () )
return e;
klass = klass->base;
}
return e;
}
// do_function - handle function declarations
void
compiler::do_function ()
{
frequire ( T_IDENTIFIER );
string name = scan.t_token;
int tkn = scan.token ();
if ( tkn == '(' )
do_regular_function ( name );
else if ( tkn == T_CC )
{
string class_name = name;
ENTRY e = package->find ( class_name );
if ( !e.is_valid () )
throw parse_error ( this, "Class '%s' not found.",
(const char *) class_name );
else if ( e.value()->v_type != DT_CLASS )
throw parse_error ( this, "'%s' is not a class.",
(const char *) class_name );
CLASS *klass = e.value()->v.v_class;
frequire ( T_IDENTIFIER );
string name = scan.t_token;
e = klass->find ( name );
if ( !e.is_valid () ||
!( ( e.type () == ST_FUNCTION ) ||
( e.type () == ST_SFUNCTION )
)
)
throw parse_error ( this,
"'%s' has to be declared as function in '%s' class.",
(const char *) name, (const char *) class_name );
frequire ( '(' );
*( e.value () ) = do_code ( name, klass, e.type () );
}
else
throw parse_error ( this, "Expecting '(' | '::'" );
}
// do_regular_function - parse a regular function definition
void
compiler::do_regular_function ( const char *name )
{
report ( "\tfunction '%s'", name );
VALUE *v = package->add ( name, ST_SFUNCTION ).value ();
if ( !v )
throw parse_error ( this, "Function '%s' already defined.", name );
*v = do_code ( name, package, ST_SFUNCTION );
}
// do_code - compile the code part of a function or method
CODE *
compiler::do_code ( const char *name, CLASS *klass, int stype )
{
unsigned char *old_cbuff = cbuff; // code buffer
int old_cptr = cptr; // code pointer
int tcnt = 1;
unsigned char stack_cbuff [ CMAX ];
// add the implicit 'this' argument for member functions
if ( klass )
{
(void) arguments [ "this" ];
methodclass = klass;
}
else
methodclass = 0;
// get the argument arglist
get_id_list ( arguments, ")" );
frequire ( ')' );
int tkn = scan.token ();
if ( tkn == ';' )
{
arguments.clear ();
return 0;
}
else if ( tkn != '{' )
throw parse_error ( this, "Expecting '{' | ';'" );
// initialize
cbuff = stack_cbuff;
cptr = 0;
// reserve space for the temporaries
putcbyte ( OP_TSPACE );
int c_tspace = cptr;
putcbyte ( tcnt );
// compile the code
putcbyte ( OP_PUSH );
int last_statement = do_block ();
if ( last_statement != T_RETURN )
{
if ( inConstructor )
{
compiler::PVAL pv;
findvariable ( "this", &pv );
rvalue ( &pv );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -