5331 lines · 168.0 KB · C++
RawDownload
/*----------------------------------------------------------------------------  ChucK Concurrent, On-the-fly Audio Programming Language    Compiler and Virtual Machine   Copyright (c) 2004 Ge Wang and Perry R. Cook.  All rights reserved.    http://chuck.stanford.edu/    http://chuck.cs.princeton.edu/   This program is free software; you can redistribute it and/or modify  it under the terms of the GNU General Public License as published by  the Free Software Foundation; either version 2 of the License, or  (at your option) any later version.   This program is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License for more details.   You should have received a copy of the GNU General Public License  along with this program; if not, write to the Free Software  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  U.S.A.-----------------------------------------------------------------------------*/ //-----------------------------------------------------------------------------// file: chuck_emit.cpp// desc: chuck instruction emitter//// author: Ge Wang (ge@ccrma.stanford.edu | gewang@cs.princeton.edu)// date: Autumn 2002 - first version//       Autumn 2004 - redesign//-----------------------------------------------------------------------------#include "chuck_emit.h"#include "chuck_vm.h"#include "chuck_errmsg.h"#include "chuck_instr.h"#include "chuck_globals.h" // added 1.4.1.0#include "chuck_parse.h" // added 1.4.2.1#include <sstream>#include <iostream> using namespace std;    //-----------------------------------------------------------------------------// function prototypes//-----------------------------------------------------------------------------t_CKBOOL emit_engine_emit_stmt_list( Chuck_Emitter * emit, a_Stmt_List list );t_CKBOOL emit_engine_emit_stmt( Chuck_Emitter * emit, a_Stmt stmt, t_CKBOOL pop = TRUE );t_CKBOOL emit_engine_emit_if( Chuck_Emitter * emit, a_Stmt_If stmt );t_CKBOOL emit_engine_emit_for( Chuck_Emitter * emit, a_Stmt_For stmt );t_CKBOOL emit_engine_emit_while( Chuck_Emitter * emit, a_Stmt_While stmt );t_CKBOOL emit_engine_emit_do_while( Chuck_Emitter * emit, a_Stmt_While stmt );t_CKBOOL emit_engine_emit_until( Chuck_Emitter * emit, a_Stmt_Until stmt );t_CKBOOL emit_engine_emit_do_until( Chuck_Emitter * emit, a_Stmt_Until stmt );t_CKBOOL emit_engine_emit_loop( Chuck_Emitter * emit, a_Stmt_Loop stmt );t_CKBOOL emit_engine_emit_break( Chuck_Emitter * emit, a_Stmt_Break br );t_CKBOOL emit_engine_emit_continue( Chuck_Emitter * emit, a_Stmt_Continue cont );t_CKBOOL emit_engine_emit_return( Chuck_Emitter * emit, a_Stmt_Return stmt );t_CKBOOL emit_engine_emit_switch( Chuck_Emitter * emit, a_Stmt_Switch stmt );t_CKBOOL emit_engine_emit_exp( Chuck_Emitter * emit, a_Exp exp, t_CKBOOL doAddRef = FALSE );t_CKBOOL emit_engine_emit_exp_binary( Chuck_Emitter * emit, a_Exp_Binary binary );t_CKBOOL emit_engine_emit_op( Chuck_Emitter * emit, ae_Operator op, a_Exp lhs, a_Exp rhs, a_Exp_Binary binary );t_CKBOOL emit_engine_emit_op_chuck( Chuck_Emitter * emit, a_Exp lhs, a_Exp rhs, a_Exp_Binary binary );t_CKBOOL emit_engine_emit_op_unchuck( Chuck_Emitter * emit, a_Exp lhs, a_Exp rhs );t_CKBOOL emit_engine_emit_op_upchuck( Chuck_Emitter * emit, a_Exp lhs, a_Exp rhs );t_CKBOOL emit_engine_emit_op_at_chuck( Chuck_Emitter * emit, a_Exp lhs, a_Exp rhs );t_CKBOOL emit_engine_emit_exp_unary( Chuck_Emitter * emit, a_Exp_Unary unary );t_CKBOOL emit_engine_emit_exp_primary( Chuck_Emitter * emit, a_Exp_Primary exp );t_CKBOOL emit_engine_emit_exp_cast( Chuck_Emitter * emit, a_Exp_Cast cast );t_CKBOOL emit_engine_emit_exp_postfix( Chuck_Emitter * emit, a_Exp_Postfix postfix );t_CKBOOL emit_engine_emit_exp_dur( Chuck_Emitter * emit, a_Exp_Dur dur );t_CKBOOL emit_engine_emit_exp_array( Chuck_Emitter * emit, a_Exp_Array array );t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, Chuck_Func * func,                                         Chuck_Type * type, int linepos, t_CKBOOL spork = FALSE );t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, a_Exp_Func_Call func_call,                                         t_CKBOOL spork = FALSE );t_CKBOOL emit_engine_emit_func_args( Chuck_Emitter * emit, a_Exp_Func_Call func_call );t_CKBOOL emit_engine_emit_exp_dot_member( Chuck_Emitter * emit, a_Exp_Dot_Member member );t_CKBOOL emit_engine_emit_exp_if( Chuck_Emitter * emit, a_Exp_If exp_if );t_CKBOOL emit_engine_emit_exp_decl( Chuck_Emitter * emit, a_Exp_Decl decl, t_CKBOOL first_exp );t_CKBOOL emit_engine_emit_array_lit( Chuck_Emitter * emit, a_Array_Sub array );t_CKBOOL emit_engine_emit_complex_lit( Chuck_Emitter * emit, a_Complex val );t_CKBOOL emit_engine_emit_polar_lit( Chuck_Emitter * emit, a_Polar val );t_CKBOOL emit_engine_emit_vec_lit( Chuck_Emitter * emit, a_Vec val );t_CKBOOL emit_engine_emit_code_segment( Chuck_Emitter * emit, a_Stmt_Code stmt,                                        t_CKBOOL push = TRUE );t_CKBOOL emit_engine_emit_func_def( Chuck_Emitter * emit, a_Func_Def func_def );t_CKBOOL emit_engine_emit_class_def( Chuck_Emitter * emit, a_Class_Def class_def );t_CKBOOL emit_engine_pre_constructor( Chuck_Emitter * emit, Chuck_Type * type );t_CKBOOL emit_engine_instantiate_object( Chuck_Emitter * emit, Chuck_Type * type,                                         a_Array_Sub array, t_CKBOOL is_ref );t_CKBOOL emit_engine_emit_spork( Chuck_Emitter * emit, a_Exp_Func_Call exp );t_CKBOOL emit_engine_emit_cast( Chuck_Emitter * emit, Chuck_Type * to, Chuck_Type * from );t_CKBOOL emit_engine_emit_symbol( Chuck_Emitter * emit, S_Symbol symbol,                                  Chuck_Value * v, t_CKBOOL emit_var, int linepos );// disabled until further notice (added 1.3.0.0)// t_CKBOOL emit_engine_emit_spork( Chuck_Emitter * emit, a_Stmt stmt );    //-----------------------------------------------------------------------------// name: emit_engine_init()// desc: ...//-----------------------------------------------------------------------------Chuck_Emitter * emit_engine_init( Chuck_Env * env ){    // log    EM_log( CK_LOG_SEVERE, "initializing emitter..." );     // TODO: ensure this in a better way    assert( sizeof(t_CKUINT) == sizeof(void *) );     // allocate new emit    Chuck_Emitter * emit = new Chuck_Emitter;    // set the reference    emit->env = env;     return emit;}    //-----------------------------------------------------------------------------// name: emit_engine_shutdown()// desc: ...//-----------------------------------------------------------------------------t_CKBOOL emit_engine_shutdown( Chuck_Emitter *& emit ){    if( !emit ) return FALSE;     // log    EM_log( CK_LOG_SYSTEM, "shutting down emitter..." );     // delete    delete emit;    emit = NULL;     return TRUE;}    //-----------------------------------------------------------------------------// name: emit_engine_emit_prog()// desc: ...//-----------------------------------------------------------------------------Chuck_VM_Code * emit_engine_emit_prog( Chuck_Emitter * emit, a_Program prog,                                       te_HowMuch how_much ){    // make sure the code is NULL    assert( emit->code == NULL );    // make sure the stack is empty    assert( emit->stack.size() == 0 );    // make sure there is a context to emit    assert( emit->env->context != NULL );    // make sure no code    assert( emit->env->context->nspc->pre_ctor == NULL );     // log    EM_log( CK_LOG_FINER, "(pass 4) emitting VM code '%s'...",        emit->env->context->filename.c_str() );    // push indent    EM_pushlog();    // log how much    EM_log( CK_LOG_FINER, "target: %s", howmuch2str( how_much ) );     // return    t_CKBOOL ret = TRUE;    // allocate the code    emit->code = new Chuck_Code;    // set the current context    emit->context = emit->env->context;    // set the namespace    emit->nspc = emit->context->nspc;    // reset the func    emit->func = NULL;    // clear the code stack    emit->stack.clear();    // name the code    // emit->code->name = "(main)";    // whether code need this    emit->code->need_this = TRUE;    // keep track of full path (added 1.3.0.0)    emit->code->filename = emit->context->full_path;    // push global scope (added 1.3.0.0)    emit->push_scope();     // loop over the program sections    while( prog && ret )    {        switch( prog->section->s_type )        {        case ae_section_stmt: // code section            // if only classes, then skip            if( how_much == te_do_classes_only ) break;            // emit statement list            ret = emit_engine_emit_stmt_list( emit, prog->section->stmt_list );            break;         case ae_section_func: // function definition            // if only classes, then skip            if( how_much == te_do_classes_only ) break;            // check function definition            ret = emit_engine_emit_func_def( emit, prog->section->func_def );            break;         case ae_section_class: // class definition            // if no classes, then skip            if( how_much == te_do_no_classes ) break;            // check class definition            ret = emit_engine_emit_class_def( emit, prog->section->class_def );            break;         default: // bad            EM_error2( 0,                "internal compiler error: unrecognized program section..." );            ret = FALSE;            break;        }         // the next        prog = prog->next;    }     // 1.4.1.0 (jack): error-checking: was dac-replacement initted?    // (see chuck_compile.h for an explanation on replacement dacs)    if( emit->should_replace_dac )    {        if( !emit->env->vm()->globals_manager()->is_global_ugen_init( emit->dac_replacement ) )        {            EM_error2( 0, "compiler error: dac replacement '%s' was never initialized...",                emit->dac_replacement.c_str() );            EM_error2( 0, " ... (hint: need to declare this variable as a global UGen)" );            ret = FALSE;        }         // (also need to make sure it was constructed; see runtime error in        // Chuck_Instr_Reg_Push_Global)    }     if( ret )    {        // pop global scope (added 1.3.0.0)        emit->pop_scope();        // append end of code        emit->append( new Chuck_Instr_EOC );        // make sure        assert( emit->context->nspc->pre_ctor == NULL );        // converted to virtual machine code        emit->context->nspc->pre_ctor = emit_to_code( emit->code, NULL, emit->dump );        // add reference        emit->context->nspc->pre_ctor->add_ref();    }     // clear the code    delete emit->code;    emit->code = NULL;     // pop indent    EM_poplog();     // return the code    return emit->context->nspc->pre_ctor;}    //-----------------------------------------------------------------------------// name: emit_to_code()// desc: ...//-----------------------------------------------------------------------------Chuck_VM_Code * emit_to_code( Chuck_Code * in,                              Chuck_VM_Code * out,                              t_CKBOOL dump ){    // log    EM_log( CK_LOG_FINER, "emitting code: %d VM instructions...",            in->code.size() );    // allocate the vm code    Chuck_VM_Code * code = out ? out : new Chuck_VM_Code;    // make sure    assert( code->num_instr == 0 );    // size    code->num_instr = in->code.size();    // allocate instruction pointers+    code->instr = new Chuck_Instr *[code->num_instr];    // set the stack depth    code->stack_depth = in->stack_depth;    // set whether code need this base pointer    code->need_this = in->need_this;    // set whether static inside class | 1.4.1.0 (ge) added    code->is_static = in->is_static;    // set name    code->name = in->name;    // set filename for me.sourceDir() (added 1.3.0.0)    code->filename = in->filename;     // copy    for( t_CKUINT i = 0; i < code->num_instr; i++ )        code->instr[i] = in->code[i];     // dump    if( dump )    {        // name of what we are dumping        EM_error2( 0, "dumping %s:", in->name.c_str() );         // uh        EM_error2( 0, "-------" );        for( t_CKUINT i = 0; i < code->num_instr; i++ )        {            // check code str | 1.4.2.1 (ge) added            if( code->instr[i]->m_codestr )            {                // print the reconstructed code str                EM_error2( 0, "%s", code->instr[i]->m_codestr->c_str() );            }            // print the instruction            EM_error2( 0, "[%i] %s( %s )", i,                       code->instr[i]->name(), code->instr[i]->params() );        }        EM_error2( 0, "-------\n" );    }     return code;}    //-----------------------------------------------------------------------------// name:// desc: ...//-----------------------------------------------------------------------------// t_CKBOOL emit_engine_addr_map( Chuck_Emitter * emit, Chuck_VM_Shred * shred );    //-----------------------------------------------------------------------------// name:// desc: ...//-----------------------------------------------------------------------------// t_CKBOOL emit_engine_resolve( );    //-----------------------------------------------------------------------------// name: emit_engine_emit_stmt_list()// desc: ...//-----------------------------------------------------------------------------t_CKBOOL emit_engine_emit_stmt_list( Chuck_Emitter * emit, a_Stmt_List list ){    t_CKBOOL ret = TRUE;     // emit->push();    while( list && ret )    {        ret = emit_engine_emit_stmt( emit, list->stmt );        list = list->next;    }    // emit->pop();     return ret;}    //-----------------------------------------------------------------------------// name: emit_engine_emit_stmt()// desc: ...//-----------------------------------------------------------------------------t_CKBOOL emit_engine_emit_stmt( Chuck_Emitter * emit, a_Stmt stmt, t_CKBOOL pop ){    // empty stmt list    if( !stmt )        return TRUE;     // return    t_CKBOOL ret = TRUE;    // next index    t_CKUINT nextIndex = 0;    // expression string    string codestr;     // loop over statements    switch( stmt->s_type )    {        case ae_stmt_exp:  // expression statement            // get str            codestr = absyn2str( stmt->stmt_exp );            // get next index | 1.4.2.1 (ge) added            nextIndex = emit->next_index();             // emit it            ret = emit_engine_emit_exp( emit, stmt->stmt_exp );            if( !ret )                return FALSE;             // need to pop the final value from stack            if( ret && pop && stmt->stmt_exp->type->size > 0 )            {                // sanity                assert( stmt->stmt_exp->cast_to == NULL );                 // exp                a_Exp exp = stmt->stmt_exp;                // hack                if( exp->s_type == ae_exp_primary && exp->primary.s_type == ae_primary_hack )                    exp = exp->primary.exp;                 // need to pop in reverse order                vector<a_Exp> pxe;                // go                while( exp )                {                    pxe.push_back( exp );                    exp = exp->next;                }                 // loop over the expression that is the statement (prior to 1.4.2.1 comment: "HACK" hmmm...)                for( t_CKINT i = pxe.size()-1; i >= 0; i-- )                // for( t_CKINT i = 0; i < pxe.size(); i++ )                {                    exp = pxe[i];                    // if decl, then expect only one word per var                    // added 1.3.1.0: iskindofint -- since on some 64-bit systems sz_INT == sz_FLOAT                    if( exp->s_type == ae_exp_decl )                    {                        // (added 1.3.1.0 -- multiply by type size; #64-bit)                        // (fixed 1.3.1.2 -- uh... decl should also be int-sized, so changed to INT/WORD)                        emit->append( new Chuck_Instr_Reg_Pop_Word4( exp->decl.num_var_decls * sz_INT / sz_WORD ) );                    }                    else if( exp->type->size == sz_INT && iskindofint(emit->env, exp->type) ) // ISSUE: 64-bit (fixed 1.3.1.0)                    {                        // is an object left on the stack for the stmt                        if( exp->s_type == ae_exp_func_call && isobj(emit->env, exp->type) )                        { emit->append( new Chuck_Instr_Release_Object3_Pop_Word ); }                        else // not an object                        { emit->append( new Chuck_Instr_Reg_Pop_Word ); }                    }                    else if( exp->type->size == sz_FLOAT ) // ISSUE: 64-bit (fixed 1.3.1.0)                        emit->append( new Chuck_Instr_Reg_Pop_Word2 );                    else if( exp->type->size == sz_COMPLEX ) // ISSUE: 64-bit (fixed 1.3.1.0)                        emit->append( new Chuck_Instr_Reg_Pop_Word3 );                    else if( exp->type->size == sz_VEC3 ) // ge: added 1.3.5.3                        emit->append( new Chuck_Instr_Reg_Pop_Word4(sz_VEC3/sz_WORD) );                    else if( exp->type->size == sz_VEC4 ) // ge: added 1.3.5.3                        emit->append( new Chuck_Instr_Reg_Pop_Word4(sz_VEC4/sz_WORD) );                    else                    {                        EM_error2( exp->linepos,                                   "(emit): internal error: %i byte stack item unhandled...",                                   exp->type->size );                        return FALSE;                    }                }            }             // see if we added at least one instruction            if( nextIndex < emit->next_index() )            {                // set codestr (for instruction dump)                emit->code->code[nextIndex]->set_codestr( codestr );            }            break;         case ae_stmt_if:  // if statement            ret = emit_engine_emit_if( emit, &stmt->stmt_if );            break;         case ae_stmt_for:  // for statement            ret = emit_engine_emit_for( emit, &stmt->stmt_for );            break;         case ae_stmt_while:  // while statement            if( stmt->stmt_while.is_do )                ret = emit_engine_emit_do_while( emit, &stmt->stmt_while );            else                ret = emit_engine_emit_while( emit, &stmt->stmt_while );            break;         case ae_stmt_until:  // until statement            if( stmt->stmt_until.is_do )                ret = emit_engine_emit_do_until( emit, &stmt->stmt_until );            else                ret = emit_engine_emit_until( emit, &stmt->stmt_until );            break;         case ae_stmt_loop:  // loop statement            ret = emit_engine_emit_loop( emit, &stmt->stmt_loop );

Lines 1–500 of 5331.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t