octal-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Octal-dev] OX++ wrapper/stub machine draft code. opinions please.


From: Dave O'Toole
Subject: [Octal-dev] OX++ wrapper/stub machine draft code. opinions please.
Date: Tue, 30 May 2000 17:59:48 -0400

[attached: odd wrapper code]

Warning: this is "hot off the presses" so to speak, so it hasn't been
tested on real machines yet. In addition, I suspect I'm going to rewrite
the wrapper; read on, I'd like to hear your opinions.  

OX++ is a wrapper for the OX_API that allows you to more easily write
Octal machines in C++. Using C++ to do machines will fix the one real
rough spot in OX_API; namely, the need to deal with "state objects."
Store your state data as members in a C++ object, and make the ox_****
callback functions map to member functions of the user-defined class. 

I decided to store the address of the user-defined C++ object in the
machine struct, just as C machines stored the address of their custom
state objects. 

Here's what I did to implement the wrapper.  

1. I declared a class OX_Machine, having several member functions
(corresponding loosely to the ox_**** functions.) 
2. I implemented the suite of ox_**** callbacks (as if writing a
machine), which do nothing but extract the "m->state" pointer from the
machine struct, cast the pointer to what I need (in this case,
OX_Machine*) and do stuff with the pointer. In this case, I forward the
data from the ox_**** calls on to the member functions of the machine
writer's object, which should be derived from OX_Machine. 

I thought that the user could just #include this header file, derive a
new class, implement the member functions, and everything would Just
Work :-). But I quickly ran into problems during coding. First, I
couldn't find any clean way to get the ox_init() wrapper to properly
build an element of the derived class the user has created. Since the
derived class doesn't even exist at this point in the compilation,
there's no way to create the object from here. 

So I made a macro called OX_CLASS, which is merely the name of the class
that you (the machine coder) are about to declare. My idea was that if
you define OX_CLASS before you include the wrapper code, the macro will
expand to the proper calls, and the ox_init() wrapper etc will make the
right call.

This didn't work either. C++ wouldn't accept references to a class that
hadn't been fully declared yet (even with explicit forward references,
which it tagged as errors) and since the new class derives from the old
class, I couldn't put it "up-front" either. Clearly the machine writer's
class declaration needs to come **in between** the OX_Machine class
declaration and the ox_**** wrappers if it's going to work. 

Splitting this into ox++preclass.h and ox++postclass.cc ended up
working, but it seems horrible now. I'd like your opinions and
suggestions. If the C-->C++ wrapper is unsightly but safe, I think it'll
be okay, since machine coders won't have to look inside the wrapper. If
the C++ wrapper as-is is unsafe/nonportable, or if there's a much better
way I'm just not seeing, please make yourself heard! :-). 

I'm experienced in C and C++, but I have not had much experience writing
bridges or glue between the two languages. I'd definitely be interested
in hearing from people who've written such things. 

-- 
@@@ david o'toole
@@@ address@hidden
@@@ www.gnu.org/software/octal
/*****************/
extern "C" {
/*****************/

inline void update_signals(machine* m, OX_Machine* x) {
  x->lin = m->lin;
  x->rin = m->rin;
  x->lout = m->lout;
  x->rout = m->rout;
}

inline OX_Machine* grab_object(machine* m) {
  return ((OX_Machine*)(m->state));
}

/* the wrapper functions themselves. primarily these hide the "state objects" 
*/ 

OX_Machine* temp; 

int ox_init(machine_type* t) {
  return OX_CLASS::initialize(t);
}

void ox_create(machine* m) {
  temp = new OX_CLASS(m);    /* call the derived class's constructor            
      */ 
  m->state = (void*)temp;    /* store the location in m->state                  
      */   
  temp->m = m;               /* make sure derived class can get to the machine 
struct */ 
}

void ox_destroy(machine* m) {
  temp = grab_object(m); 
  delete temp; 
}

int ox_work(machine* m) {
  temp = grab_object(m);
  update_signals(m, temp); 
  return temp->work();
}

void ox_update(machine* m) {
  temp = grab_object(m);
  temp->update(); 
}

const char* ox_describe(int which, param value) {
  return OX_CLASS::describe(which, value);
}


} /* end extern C */ 
/*
* $Header$
* (C) 2000 David O'Toole address@hidden $Date$
* $Revision$
* 
* OX++.H
* This file is the lightweight C++ wrapper for the OX_API.
* It's part of the GNU OCTAL project; see http://www.gnu.org/software/octal
* for more information.  
*
* No, this interface isn't pretty on the inside. But neither is C++ :-)
*
* This software is distributed under the terms of the
* GNU General Public License (GPL). Read the included file
* COPYING for more information. 
* 
* $Log$
*
*/

/* Important notes on usage. 
 * ------------------------
 * 1. #define OX_CLASS to be the name of your machine's class
 * 2. #include "ox++.h"
 * 3. derive your machine's class from OX_Machine, adding new
 *    members/functions as needed 
 * 4. OX_Machine::m is the pointer to a struct machine
 *    which is formatted as in the OX_API Developer's Guide
 * 5. You no longer need to think about state objects. 
  */ 

#ifndef _oxplusplus_h_
#define _oxplusplus_h_ "@(#)myfile.h $Revision: 1.1 $"

#ifndef OX_CLASS
#error OX++ error; you must #define the macro OX_CLASS before using OX++
#endif

extern "C" {
#include "octal.h"
#include "machine.h"
}

class OX_Machine {
 public: 
  OX_Machine(){};
  OX_Machine(machine* m) {};        
  virtual ~OX_Machine() {};
  static int initialize(machine_type* t) {};   
  virtual void update() = 0;                    
  static const char* describe(int which, param value) {}; 
  virtual int work() = 0;  
 
  machine* m; 
  samp *lin, *rin, *lout, *rout; 
};

#endif /*_oxplusplus_h_*/
/* $Source$ */










reply via email to

[Prev in Thread] Current Thread [Next in Thread]