⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 compiler.cpp

📁 c-smile 一个语法类似与JS 又有点像C++的 编译器
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/*
*
* 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 + -