Abstract:
The present invention provides an in-line wrapper sentry for a programming language to detect events and to transparently extend the behavior of the events.

Description:
This invention was made with Government support under Contract No. DAAB07-90-C-B9 20 awarded by the Defense Advanced Projects Research Agency (DARPA) and administered by U.S. Army CECOM. The Government has certain rights in this invention. 
    
    
     This application is a Continuation of application Ser. No. 08/006,061, filed Jan. 15, 1993, abandoned. 
    
    
     The present application incorporates by reference herein the following pending U.S. applications: Serial No. 07/516,369, filed Apr. 30, 1990, entitled &#34;Apparatus and Method for Adding an Associative Query Capability to a Programming Language&#34;; Serial No. 07/526,215, filed May 21, 1990, entitled &#34;An Apparatus and Method for Providing a Facility for Managing Versions and Configurations of Persistent and Transient Objects&#34;, abandoned; and Serial No. 07/531,493, filed May 30, 1990, entitled &#34;A System and Method for Database Management Supporting Object-Oriented Programming&#34;, now U.S. Pat. No. 5,297,279. 
     Technical Field of the Invention 
     This invention relates to object-oriented programming languages and object-oriented database management systems and more specifically to a method and apparatus for in-line wrapper sentry to be used to detect events and to transparently extend the behavior of events. 
     BACKGROUND OF THE INVENTION 
     As illustrated in FIG. 1, a computer includes a CPU compiler (100) to control the computer, memory (120) to store information secondary storage (130) to store additional information, input devices (110) to input information, and output devices (140) to output information. The CPU (100) may include as illustrated in FIG. 2 a data management system (215). The database management system (215) includes a number of functional components including a file manager (212), which manages the allocation of space on disk storage and the data structures used to represent information stored on disk (210), a database manager (214) to provide the interface between the low-level data stored in the database and the applications programs and queries submitted to the system, a query processor (220), which translates statements in query language into low-level instructions that the database manager understands, and attempts to transform a user&#39;s request into an equivalent but more efficient form, thus finding a good strategy for executing the query, a data manipulation language pre-compiler (218), which converts Data Manipulation Language (DML) statements embodied in an application program to normal procedural calls in the host language and interacts with the query processor in order to generate the appropriate code, and the Data Definition Language (DDL) compiler to convert the Data Definition Language to a set of tables containing metadata. 
     One such database is the Texas Instruments&#39; Open Object-Oriented DataBase (Open OODB), which employs the Open OODB computational model, allowing developers to define behavioral extensions of events, which is an application of an operation to a particular set of objects. 
     It is desirable that the database be open such that developers or researchers can control, modify or extend some part(s) of its architecture or implementation. The Open OODB Meta architecture provides procedures to declare the events to be extended to a sentry manager, to detect events with sentries and to transparently extend the behavior of events by policy managers. This general architecture is described in Wells, Blakeley, Thompson, &#34;Architecture of an Open OODB&#34;, IEEE Computer, Oct., 1992, p. 74. 
     While it is desirable to design a database so that no extensions or additions are ever required, the programmer is often faced with the need to modify the database to change existing data or add additional data in order to provide for functions that have not been heretofore envisioned. One method of conceptually envisioning behavioral extensions to objects is providing a new class which inherits from a base class for handling a specific extension or set of extensions. However, this method is not preferred and it is difficult to implement such behavioral extensions in a language such as C++. This approach generally causes the program to generate multiple inheritances even though a single inheritance had been previously used. Thus, C++ programs that execute properly under single inheritance, often provide erroneous results using multiple inheritance. 
     Objects are included in a &#34;universe of objects&#34; which are partitioned into &#34;environments&#34; by &#34;environmental attributes&#34;. These environments and boundaries of the environments identify where extensions may be required. For example, an address space in which an object resides is an environmental attribute. 
     FIG. 3 illustrates the design space for sentry managers and illustrates the various functions of sentry managers. The sentry manager is the locus for specifying events to be extended, and, as part of the task of the sentry manager, the sentry manager is responsible for deploying sentries to detect extended events. A common interface must exist between the user&#39;s program and this policy manager by which sentries call on policy managers. This common interface passes sufficient information so that the policy manager can decide if an extension is necessary and then perform the extension. The policy manager additionally executes the event if in accordance with the policy of the policy manager. This information must be obtained by the sentry. A goal of the sentry is to maintain the seamlessness of the database. This seamlessness generally requires language that is specific with respect to the sentry. Thus, new behaviors or capabilities can be added without the programmer being aware of the new behavior. 
     With sentries, speed and power are usually conflicting properties. Powerful sentries are generally slower than less powerful sentries. As a database matures, the less powerful but faster sentries are generally desirable while with a new database, powerful sentries are needed. In order to change sentries to meet the needs of the database, a large amount of pre-programming effort must be expended. It is desirable to have a fast yet powerful sentry and a sentry which can be easily changed. 
     FIG. 4 illustrates the design space for sentries and illustrates the functions of sentries. The primary function of sentries is to detect events and to pass control to a policy manager which controls and performs the actual extension if it is determined that an event should be extended. Sentry mechanisms differ in coverage, performance, selectivity and dynamism of deployment and removal. 
     One of the functions of computer software programs is to manipulate data by the use of programming language instructions. Typically, the data requirements of the computer software program change over the period of time that the computer software program is used. If the data manipulated by the computer software program was not shared by other computer software programs, changes in the data configuration would present little or no problems. However, generally the data is shared between different computer programs, and it is essential that the data and data format be compatible between the different computer programs. If output data produced by one version of the computer program is retained to be reused by other computer programs, the data output by subsequent versions of the same computer program must be at least compatible with the original output data. This is a significant problem since subsequent versions of the program may require either different schematics or formats for the output data. Thus, both the problems of multiple program instances of the data and the use of old data by subsequent versions of the same computer program are problems of configuration management and schema evolution. 
     Manually changing the software code to include these changing data requirements is both costly and error prone. It is estimated that between 70-90% of all software budgets are spent maintaining existing code of these computer programs. While a portion of the software budgets are used to fix errors within the computer programs, a substantial portion of the software budget is spent on implementing changes to the computer program so that these programs are able to access the data which has been changed. Thus, any automation which solves the problem of evolving software has the potential for enormous savings. 
     A prerequisite to making these program changes involves the detection of the instances when the database is accessed. The mechanism for interrupting operation so that some additional activity can occur are widely available in computer hardware and software. Generally, such interruptions or traps are used for very specific, limited purposes. Thus, the trapping mechanism combined with the protocol for permitting the entity performing the trapping to invoke an arbitrary extension is known as a &#34;sentry&#34;. The protocol, for example, the policy manager, for communicating with the behavior modifier, has been known. However, variability with respect to the interruption of the operation exists only in the trapping aspect of the sentry mechanism. 
     One such trapping mechanism is hardware interrupts. Many computers include hardware interruption mechanisms that can be used to interrupt the flow of machine instruction execution between existing machine instructions. Such hardware interrupts typically correspond to the arrival of data at an input port or a machine register reaching a pre-determined value. Thus, these hardware interrupts are extremely machine-specific and would be useful for only a small percentage of possible events. Furthermore, these hardware interrupts are defined only at very specific levels of abstraction, for example, machine level instructions, and are not defined for higher level programs which need to be extended, such as C++. 
     Another mechanism for interrupting some form of operation is bad data traps. Many hardware platforms or software run-time systems define certain data values or type tags as &#34;invalid&#34; to be encountered under particular circumstances. If one of these invalid data types or type tags are encountered, an exception occurs which can be trapped. Texas Instruments implemented such a bad data trap sentry based on employing bad data tags on the Texas Instruments&#39; Explorer LISP machine. One large disadvantage of this type of sentry is that it is platform-specific. That is, the trap can only be activated during memory access. The trap cannot be activated during a function dispatch. Furthermore, this type of sentry tends to interfere with other system primitives that are, in fact, permitted to use these values which have been designated as &#34;illegal&#34;. This sentry trap appears to be inherently unstable in that the interaction between system primitives are very subtle and correspondingly vary unpredictably if the other primitives are modified. Additionally, the changes in the system primitives could be overlooked since operating system developers generally presume that only other operating system developers program at such a low level, and, as a consequence, the operating system developers are not required to maintain consistency of these features between releases. 
     Another type of mechanism for interrupting operation is virtual memory traps. Most modern computers employ the concept of &#34;virtual memory&#34;, which permits programs to address memory which is outside of the physical memory available. When the program attempts to access the data item not actually in physical memory, a trap occurs, and the memory page containing the data item not in memory is brought into real memory. Traps of this type which have been modified have been used with limited success in some OODBs to permit objects that have not been retrieved from object store the database to be transparently retrieved. This particular technique has at least three significant drawbacks. First, the modifications to the normal virtual memory mechanism are hardware-specific and operating system-specific to make the modifications applicable to database applications. As a consequence, such a technique would be inappropriate for programming languages such as C++. Second, only when a data item is touched can the data item be trapped. Thus, it is not possible to trap the execution of a particular function or method associated with an object. This limitation precludes application of this mechanism for several kinds of extensions, for example, index maintenance. Lastly, since this type of trapping is based on memory addresses, it is not clear how programs which are compiled with one presumption with respect to the physical layout of the data could correctly function with the data created by a second program having a different presumption with respect to the physical layout of the data. This is a significant drawback since modifications to the program itself to add new features frequently change the physical layout. As a consequence, schema evolution becomes significantly more difficult by employing this type of trapping mechanism. 
     A further type of interruption mechanism is delegation. Delegation is an object-oriented technique where class instances are permitted to ask a &#34;delegate&#34; object how to perform operations that they themselves do not know how to perform. Delegation has not been employed in C++. 
     A further mechanism for interrupting some operation is a before-method, after-method and around-method. Certain programming language, such as LISP and the extension of LISP, the Common LISP Object System (CLOS), provide language mechanisms to dynamically modify the behavior of certain functions associated with particular classes of objects. These mechanisms do not exist is languages such as C++. 
     A further mechanism for interruption is changes to function dispatch mechanisms. The CLOS has language features collectively known as the &#34;Meta Object Protocol&#34; that allows for the redefinition of how functions are to be dispatched, for example, prepared for execution and then executed. The Meta Object Protocol can be used to modify dispatch so that any declared extensions are executed as called for by the Open OODB Meta architecture. This technique is not available for C++ programs, and applies only to member functions of classes, making it unable to cover direct slot accesses of the object state. 
     Another mechanism for interrupting some operation is virtual function modification. With normal C++ language, there is a single, immutable &#34;virtual function dispatch table&#34; for each object class. The researchers at the University of Utah have prototyped a mechanism to allow each instance of a class to have a distinct virtual function dispatch table. Each of these tables can be independently populated with modified virtual functions that extend or change behavior. This type of mechanism cannot be used to trap a memory access, precluding this type of mechanism&#39;s use to ensure the residency of an object which is using a virtual function. An additional problem is that if a wide variety of tables are managed, the application&#39;s code size increases dramatically. 
     An additional mechanism for interrupting some type of operation is a &#34;surrogate object&#34;. This surrogate object represents in some manner another object which may or may not be present in physical memory. The surrogate object intercepts all messages directed at the actual object and in fact performs any necessary actions before forwarding the messages to the actual object for execution. Additionally, the surrogate object may cause the actual object to be instantiated, for example, by retrieving the actual object from a database. The disadvantage of surrogate objects with respect to C++, is that the state of the actual object can be manipulated by the C++ program without the member functions of the class of the object being monitored. As a consequence, the object can be affected without activating the sentry, resulting in a semantic error that would cause the behavioral extension to be omitted. 
     SUMMARY OF THE INVENTION 
     In view of the above problems associated with the related art, it is an object of the present invention to provide an apparatus and method employing an in-line wrapper sentry for languages such as the C++ programming language. 
     Another object of the present invention is to provide an apparatus and method extending either the operation of the program or the data manipulated by the program to existing C++ object type/classes, for example, persistence, versioning, indexing, replication and security. 
     It is another object of the present invention such that these features be automatically embedded by a language preprocessor which does not require modifications to the language compiler. 
     It is another object of the present invention to reduce the cost and increase the accuracy of modifying existing or new computer programs to add behavioral extensions. 
     Another object of the invention is to reduce maintenance costs and information loss. 
     And lastly, an object of the invention is to transparently extend the behavior of normal operations (events). 
     The present invention transparently extends the behavior of normal operations or events without requiring language computer modifications. The present invention reduces cost and information loss by providing the in-line wrapper sentry for languages such as C++. 
     These and other features of the invention that will be apparent to those skilled in the art from the following detailed description of the invention, taken together with the accompanying drawings in which: 
    
    
     DESCRIPTION OF THE DRAWINGS 
     FIG. 1 is a block drawing diagram of a computer; 
     FIG. 2 is a block diagram of a data management system and associated disk storage; 
     FIG. 3 is a diagram illustrating the various functions of sentry managers; 
     FIG. 4 is an illustration of the function of sentries; 
     FIG. 5 is an illustration of a multiple inheritance database; 
     FIG. 6 is an illustration of a single inheritance database; 
     FIG. 7 is a block diagram of the compiler and preprocessor; and 
     FIG. 8 is a block diagram illustrating the sentry being involved with a &#34;pre-allocation&#34; strategy. 
     FIG. 9 is a block diagram illustrating the operation of the preprocessor. 
    
    
     DETAILED DESCRIPTION OF THE INVENTION 
     The present invention treats all extendable classes as &#34;logically&#34; inheriting from a &#34;conceptual&#34; base class of &#34;extendable-objects&#34;. This conceptual base class defines the necessary structures and functions to make all classes inheriting from this conceptual base class include a &#34;sentry&#34;. Unlike the case of normal inheritance, the class of &#34;extendable-objects&#34; is never seen or actually compiled by the C++ compiler. Instead, all of the classes logically inheriting from the class of &#34;extendable-objects&#34; are modified by a language preprocessor to insert the defined structures and functionality into each actual class. These classes modified by the preprocessor, are then compiled by the C++ compiler. Thus, by generating the sentry code before the time the C++compiler compiles the program, the artificial multiple inheritance created by the C++ compiler as described above does not occur, and to replace the C++compiler is not required. A normal C++ compiler will ensure that pointer conversion, base class offsets, friend functions, etc., operate properly. These functions operate properly because a normal C++ compiler is employed. 
     As illustrated in FIG. 7, the preprocessor accepts as input the code program requiring the extendable-objects to be added; the pre-preprocessor processes the input program and outputs an equivalent program with the extensions including sentries added. The outputted equivalent program, when linked with policy performer modules, performs all the added behavioral extension to an object when the equivalent program is executed. The preprocessor as illustrated in FIG. 7 would be positioned upstream of the compiler for execution by the database manager (214). The preprocessor adds the behavioral extensions to an object in 2 steps: 
     (i) the preprocessor preprocesses the input program and obtains information with respect to the input program; 
     (ii) the preprocessor then generates an equivalent program from the information and the preprocessed program is outputted with the extended classes. 
     As the preprocessor processes and collects information with respect to the input program, the preprocessor uses a generic C++ processor that processes and collects all C++ declarations, in particular, the class/struct declarations. With respect to the class, the preprocessor collects, in particular, the members, constructor/destructor, copy constructor and assignment operator, inheritance hierarchy - base class information, friend functions/classes, function properties such as virtual, non-virtual and static, and accessibility of state variables, for example, public, private, or protected. 
     In addition to the above function, the preprocessor generates and then outputs the equivalent program with the extended classes. This is accomplished by extending every member function of a class with a sentry that traps certain events, triggers an action to successfully complete the action corresponding to the event, and resumes normal execution. A typical sentry code is illustrated in Example 1. 
     EXAMPLE 1: 
     
         ______________________________________1:    if (event.sub.-- set()) {2:     save.sub.-- arguments();3:     void *adjusted.sub.-- ptr = adjust.sub.-- to.sub.-- most.sub.-- derived.sub.-- object();4:     do.sub.-- action(adjusted.sub.-- ptr,address of function to execute); }______________________________________ 
    
     As illustrated, line 1 determines if an event is set on this object. If the event is set, the formal parameters of the function are saved in special locations as specified by line 2. Line 3 adjusts the object value to point to the most-derived (the highest or root derived object in the inheritance lattice) object. Line 4 performs the action associated with the event and passes the function to the event to call when executed. The address of the function corresponds to the actual function that the programmer intended, but has been modified and renamed by the preprocessor. 
     Example 2, which follows, illustrates the extension of all non-static member functions by sentry code, except constructors/destructor. 
     EXAMPLE 2: 
     
         ______________________________________1:    classA {2:     int a;3:4:     public:5:     int get.sub.-- a() {return(a);}6:    };is extended to7:    classA {8:     int a;9:     public:10:    ORIGINAL.sub.-- get.sub.-- a() {result = a;return(result);}11:    static get.sub.-- a.sub.-- static.sub.-- oodb.sub.-- fn.sub.--  (void *ptr) {12:     return(((A *)ptr-&gt;ORIGINAL.sub.-- get.sub.-- a());13      }14:    int get.sub.-- a() {15:     if (Events.sub.-- Placed(A::get.sub.-- a)16:     void *real.sub.-- this = this-&gt;adjust.sub.-- to.sub.-- most.sub.--   derived.sub.-- object();17:     // no arguments - omit save.sub.-- arguments();18:     do.sub.-- action(real.sub.-- this,&amp;get.sub.-- a.sub.-- static.sub.  -- oodb.sub.-- fn.sub.--);19:     return(result);20:     }21:     else return(ORIGINAL.sub.-- get.sub.-- a());22:    }23:   };24:      do.sub.-- action(real.sub.-- this,&amp;get.sub.-- a.sub.-- static.sub   .-- oodb.sub.-- fn.sub.--);______________________________________ 
    
     As illustrated by Example 2, lines 1-6, correspond to the user&#39;s original class code for example a predetermined code. Lines 7-23 illustrate the output of the generated class that has been extended to trap different kinds of events for example directly after the predetermined code. Note, each member function such as the member function on line 5 (&#34;get --  a&#34;) is modified and renamed to &#34;ORIGINAL --  get --  a&#34; as in line 10. An additional &#34;get --  a&#34; function as illustrated on lines 14-22 is generated, containing the trap-event code as illustrated in lines 15-20. The code of the generated static function is illustrated in lines 11-13 and these lines will be invoked by the policy manager of events which are trappable for this object. Line 13 invokes the &#34;ORIGINAL --  get --  a&#34; if the object of a type class A. Note, that in this case, the argument &#34;void *ptr&#34; will be of type class A. 
     Line 15 determines if this object includes any events to trap. If the object has events to trap, then lines 16-19 are executed. Line 16 adjusts the pointer address of the object to point to the most-derived object. Line 17 saves the values of the argument passed to the function &#34;get --  a&#34; in storage. In this specific case, since the function &#34;get --  a&#34; includes no arguments are saved. Line 21 transfers control to the routine that invokes the appropriate action routines, such as event-handlers, for this event; these are typically the policy managers of the event. The address of the &#34;get --  a --  static --  oodb --  fn --  &#34; is passed as an argument in line 18. This function will be invoked after control is returned from the event-handling routines. Instruction 24 illustrates that the behavioral operation is executed before the original operation. The behavioral operation could be executed after the original operation. 
     The sentry code is complex due to the fact that any arbitrary behavior can be added to class A. As illustrated by Example 3, which follows, if only persistence behavior is added to the class, the code is simpler than the above example. 
     EXAMPLE 3: Only persistence behavior being added to the class A. 
     
         ______________________________________1:    class A {2:     int a;3:     public:4:     int get.sub.-- a() {return(a);}5:    };is extended to6:    class A {7:     int a;8:     public:9:     inline int get.sub.-- a.sub.-- oodb.sub.-- fn.sub.-- () {10:    return(a);11:    }12:    int get.sub.-- a() {13:     if (Is.sub.-- Persistent()) {14:     void *real.sub.-- this = this-&gt;adjust.sub.-- to.sub.-- most.sub.--   derived.sub.-- object();15:     Trap.sub.-- Fault(real.sub.-- this);16:     }17:     return(get.sub.-- a.sub.-- oodb.sub.-- fn.sub.-- ());18:     }19:   };______________________________________ 
    
     As illustrated in the above example, for each user-defined member function, for example, &#34;get --  a&#34; as illustrated in line 4, an in-line member function is automatically generated; for example, &#34;get --  a --  oodb --  fn --  &#34; as illustrated in line 9 is automatically generated. For example lines 1-5 corresponds to the predetermine code and lines 6-19 are positioned directly after the predetermined code. 
     Note, the user function name, for example, &#34;get --  a&#34; is changed to, for example, &#34;get --  a --  oodb --  fn --  &#34;. Additionally, a new &#34;get --  a&#34; is generated, for example, in lines 12-18, and the sentry code, for example, in lines 13-16, is positioned before the call of the actual code of &#34;get --  a --  oodb --  fn --  &#34; as in line 17. The instruction on line 13 determines if the object is persistent and requires to be fetched from the persistent store such that the object is stored in an external memory such as a disk. The instruction on line 14 modifies the object address to point to the most-derived object. The instruction on line 15 performs the object fault and fetches the most-derived object from the persistent store. Lastly, the instruction on line 17 resumes execution by a call to &#34;get --  a --  oodb --  fn --  &#34;. 
     As illustrated in FIG. 8, the Trap --  Fault of instruction line 15 uses a &#34;pre-allocation&#34; strategy when fetching objects from the persistent store. Thus, only the initial part of the object is fetched and the remaining portions of the object&#39;s closure is postponed until it is absolutely necessary that these other remaining portions be brought into main memory. This &#34;pre-allocation&#34; strategy allocates empty space for the object, but does not immediately fill in the values for the object residing in the persistent store. 
     Thus, when this allocated but unused space is in fact accessed, the sentry &#34;object fault&#34; extension fetches the object state from the persistent store and fills in the necessary values. 
     As illustrated in FIG. 8, the member function determines if the object fault sentry is present. If the object fault sentry is not present, normal execution continues. However, if the object fault sentry is present, the object fault handler is invoked; the persistent object managing routine is invoked which fetches the remaining object from the persistent store, then object translation of the object is performed; and finally object construction of the object is performed before returning control to normal execution. 
     This &#34;pre-allocation&#34; strategy has several advantages. First, not all the objects from the persistent store are required to be fetched. This demand-driven manner or on-use manner saves memory space since the in-memory space is only used as required. Additionally, this &#34;pre-allocation&#34; strategy saves time since time is not wasted accessing the portion of the object from the persistent store. Additionally, the &#34;pre-allocation&#34; strategy of the present invention saves time, since the time that would be required to fill in the values is saved. 
     The preprocessor additionally generates a &#34;copy constructor&#34; and/or &#34;assignment operator&#34; in accordance with a predetermined indicator which is set by the user. The copy constructor functions when an argument of type &#34;class&#34; is included as an argument, and the assignment operator is used when one object is assigned to another object. The language such as C++ could automatically generate these functions, if not explicitly defined by the user with the default semantics of memberwise copying. If the classes do not define either or both of the &#34;copy constructor&#34; and the &#34;assignment operator&#34;, the preprocessor generates these two functions with corresponding sentry-code inserted. The function of the &#34;copy constructor&#34; and the &#34;assignment operator&#34; traps certain events as well as exhibits the behavior of the default copy constructor and the default assignment operator as defined by the language. 
     These copy constructor and assignment operators are generated seamlessly and uniformly without programmer intervention and without affecting the default semantics of the copy constructor function and the assignment operator function as defined by the language. 
     Example 4, which follows, is an example of an automatically generated copy constructor and assignment operator. 
     EXAMPLE 4: 
     
         ______________________________________1:    class A { . . .2:    A(const A &amp;arg) {3:     if (Is.sub.-- persistent(&amp;arg)) {4:     void *real.sub.-- this = this-&gt;MostDerivedObject();5:     TrapFault(real.sub.-- this);6:    }7:    char *this.sub.-- ptr = (char *)this, arg.sub.-- ptr = (char *)&amp;arg;8:    for (i = 0; i &lt; sizeof(*this); ++i)9:     *this.sub.-- ptr++ = *arg.sub.-- ptr++;10:   };11:   A &amp;operator=(const A &amp;arg) {12:    if (Is.sub.-- Persistent(&amp;arg)) {13:    void *real.sub.-- this = this-&gt;MostDerivedObject();14:    TrapFault(real.sub.-- this);15:    }16:    char *this.sub.-- ptr = (char *)this, arg.sub.-- ptr = (char *)&amp;arg;17:    for (i = 0; i &lt; sizeof(*this); ++i)18:    *this.sub.-- ptr++ = *arg.sub.-- ptr++;19:    return(*this);20:   }; . . .21:   };______________________________________ 
    
     As illustrated in Example 4, the instructions of lines 1-21 are a definition of a class that has defined neither a copy constructor nor an operator instructor. The instructions for the copy constructor generated with an appropriate sentry code for persistent behavior extension only, is illustrated in the above lines 2-10. The instructions for assignment operator generated with the appropriate sentry code for the &#34;operator=&#34; are illustrated in lines 11-20. The instructions on lines 3 and 12 check whether the object is persistent and correspondingly needs to be fetched from the persistent store; the instructions on line 4 (and 12) is executed to adjust the address pointed to by &#34;arg&#34; to point to the most derived object, for example, the most derived object faulted as compared to a portion of the most derived (sub-class). The instructions on line 5 (and 13) forms a fault on the object to fetch the object from the persistent store. The instructions on lines 7-9 and 16-18 performs memberwise copying of the object as required by the C++ default copy constructor and assignment operator semantics. 
     Additionally, all classes are extended to inherit from a common &#34;virtual&#34; base class for fast and efficient checking of events placed on an object. While this is not a requirement in our invention, it is an alternative for implementing checking of events efficiently. There is at least one copy of this special base class in any inheritance hierarchy, and this base class contains a bit map of event information to indicate whether any event or extensions have been added to this object and which event or extensions have been added. Normally, when no behavioral extensions have been added to an object, this common &#34;virtual&#34; base class results in a minimal-run time performance penalty. A bit in the bitflag is used to indicate whether an object is marked for other common extensions, such as persistence. Additionally, less common behavioral extensions can be indicated through a more expensive out-of-line routine. 
     As indicated in Example 5, the common &#34;virtual&#34; base class information is extended from user instruction of line 1. 
     EXAMPLE 5: 
     
         ______________________________________1:      class A {. . .};is extended to2:      class A : public virtual.sub.-- Wrapper.sub.-- State {. . .}3:      class.sub.-- Wrapper.sub.-- State {4:       unsigned int any.sub.-- event:1;5:       unsigned int persistent:1;6:       unsigned int version:1;7:       unsigned int event1:1;    . . .    . . .   };______________________________________ 
    
     As can be seen from the above example, the instruction on line 2 illustrates extending the class definition as illustrated in line 1 to inherit &#34;virtually&#34; from a &#34; --  Wrapper --  State&#34;. The instruction on line 4 defines a member, &#34;any --  event&#34;, and if the member is set, that specifies that an extension is added to this object. The instruction of line 5 illustrates that another is member &#34;persistent&#34;, and if set, specifies that an object is extended to be persistent. In a similar fashion, the instruction of lines 6-7 defines members that specify if a particular extension, for example, &#34;versioning&#34; is added to an object of this class. 
     FIG. 9 illustrates the operation of the preprocessor. Possible code modifications by the user are added to an application C++ source code to obtain a modified application C++ source code. The preprocessor preprocesses the modified application C++ source code to parse the C++ code and insert sentries into the C++ code. The sentried application C++code is transferred to a conventional C++ compiler. From this, sentried application object code is developed and subjected to a conventional linker to result in sentried executable application code. 
     While the above-mentioned technique was illustrated by use of the OODB, the invention can be equally used in the backplane of an object service architecture, such as that developed by the Object Management Group (OMG). 
     The use of the in-line wrapper sentry technique was illustrated with the C++ programming language operations and objects to support varying database capabilities. However, the technique could be equally applied to C++ programs containing no database, for example, by adding transient versions, monitoring or simulations. The technique additionally could be used with C++ programs involving distributed data and sharing across computer networks. Additionally, the technique could be used by adding a general delegation capacity to C++programs. 
     Despite the fact that the in-line wrapper has been explained with respect to the C++ language, the in-line wrapper technique could equally apply to other programming languages in which objects have interface functions to be extended and can be accessed without using interface functions. 
     Tables 1 and 2 illustrate the output of the preprocessor for a program which has been extended to support the &#34;persistent&#34; behavior. Tables 3-10 illustrate the implementation of the preprocessor module which generates the in-line wrapper. 
     Other Embodiments 
     In addition to C++, other languages could be used, such as Ada, Pascal, Algol, and Cobol. These languages are extended with object-oriented capabilities, which include encapsulation, method or inheritance. 
     Although the present invention has been illustrated by use of a program language preprocessor, the present invention could be installed by a compiler. 
     Additionally, whether or not the compiler or preprocessor is employed, a file could be maintained. The members of the file corresponds to the different classes and would indicate whether or not these particular classes are to be sentried or not sentried. Additionally, the class constructs that are associated with a sentry manager could be a C++ language annotation, for example, a key word like &#34;sentry&#34; that corresponds to the class, appearing with the class definition in the programming source code. 
     Additionally, the new behavioral class extensions could be added to the central manager or existing behavioral extensions could be removed at run-time, for example, occurring during the lifetime of an executing computer program. Additionally, after the sentry detects the event, a collection of behavioral extensions to the event could be executed. 
     Additionally, if the class contains &#34;public state&#34; wherein the access to the class is unrestricted, the storage area to accommodate an instance of the class is pre-allocated. However, the class is still extended with persistent behavior. Furthermore, if the behavior is persistent, distribution or any materialization operation then the objects can be fetched on demand. Lastly, examples of the extended behavior include versioning, persistence, replication management, security access control, encryption/decryption, maintaining indices, object-type access, distribution, performance monitoring or maintaining dependency nets. 
     Although the present invention and its advantages have been described in detail, it should be understood that various changes, substitutions and alterations can be made herein without departing from the spirit and scope of the invention as defined by the appended claims. 
     
                                           TABLE 1__________________________________________________________________________/*  ********************************************                    *//*  Original class definition                    *//*  ********************************************                    */class OBJECT {private:int i;OBJECT *self;public:Object.sub.-- i( ) { return ( i ) ; } ;OBJECT *Object.sub.-- self( ) { return ( self ) ; } ;OBJECT( ) { i = ++I ; self = this ; } ;,;/*  ********************************************                    *//*  EXTENDED class definition for Persistence Behavior                    *//*  and object TRANSLATION *//*  ********************************************                    */class OBJECT : public virtual.sub.-- Wrapper {int i;class OBJECT *self ;public:ORIGINAL.sub.-- Object.sub.-- i( ){ return ( i ) ; } ;Object.sub.-- i( ) {if (.sub.-- Wrapper.sub.-- Trap.sub.-- Flag( ) == 1) {int sz;char *classname;void (*fn1)(voil *),(*fn2)(void *,int);OpenOODB-&gt;TrapFault(((OBJECT *)this)-&gt;oodb.sub.-- GetRealObj(sz,classname,fn1,fn2));.sub.-- Wrapper.sub.-- Set.sub.-- Trap.sub.-- Flag(0);return(ORIGINAL.sub.-- Object.sub.-- i( )};} ;class OBJECT *ORIGINAL.sub.-- Object.sub.-- self( )    { return ( self ) ; } ;class OBJECT *Object.sub.-- self( ) {if (.sub.-- Wrapper.sub.-- Trap.sub.-- Flag( ) == 1) {int sz;char *classname;void (*fn1)(void *), (*fn2)(void *, int);OpenOODB-&gt;TrapFault(((OBJECT *)this)-&gt;oodb.sub.-- GetRealObj(sz,classname,fn1,fn2));.sub.-- Wrapper.sub.-- Set.sub.-- Trap.sub.-- Flag(0);}return(ORIGINAL.sub.-- Object.sub.-- self( )};} ;OBJECT( ){ i = ++ I ; self = this ; } ;class OBJECT &amp;operator=(const class OBJECT &amp;arg) {if (arg..sub.-- Wrapper.sub.-- Trap.sub.-- Flag( ) == 1) {int sz;char *classname;void (*fn1)(void *),(*fn2)(void *,int);OpenOODB-&gt;TrapFault(((OBJECT &amp;)arg).oodb.sub.-- GetRealObj(sz,classname,fn1,fn2));((OBJECT &amp;)arg) ..sub.-- Wrapper.sub.-- Set.sub.-- Trap.sub.-- Flag(0);}{int i;char *ptr = (char *)this,*ptr1 = (char *)&amp;arg;__________________________________________________________________________ 
    
     
                                           TABLE 2__________________________________________________________________________  for (i = 0; 1 &lt; sizeof(*this); ++i) *ptx++ = *ptx1++;}return(this);};OBJECT(const class OBJECT &amp;arg) {if (arg..sub.-- Wrapper.sub.-- Trap.sub.-- Flag( ) == 1) {int sz;char *classname;void (*fn1)(void *),(*fn2)(void *,int);OpenOODB-&gt; TrapFault(((OBJECT &amp;)arg).oodb.sub.-- GetRealObj(sz,classname,fn1,fn2))((OBJECT &amp;)arg)..sub.-- Wrapper.sub.-- Set.sub.-- Trap.sub.-- Flag(0);}(int i;char *ptr = (char *)this,*ptr1 = (char *)&amp;arg;for (i = 0; i &lt; siefof(*this); ++i) *ptr++ = *ptr1++;}};OBJECT(classrXorOoDb *) { } ;OBJECT(class XorOoDb *) { oodb.sub.-- copy.sub.-- self( ); } ;in oodb.sub.-- copy.sub.-- self( ) {if (|(self))xor.sub.-- pointer(((void *)(this-&gt;self)),((void *)(&amp;this-&gt;self)),sizeof(int),0);else (self)-&gt;persist((char *)0,1,self,&amp;this-&gt;self,0);return(0),} ;static void oodb.sub.-- staticReCopySelf(void *ptr,int flag) {new ((OBJECT *)ptr) OBJECT((class rXorOoDb *)0);((OBJECT *)ptr)-&gt;.sub.-- Wrapper.sub.-- Set.sub.-- Trap.sub.-- Flag(flag);} ;static void oodb.sub.-- staticCopySelf(void *ptr) {new ((OBJECT *)ptr) OBJECT((class XorOoDb *)0);} ;private:virtual void *oodb.sub.-- GetRealObj(int &amp;sz,char *&amp;classname,      void (*&amp;fn1)(void *),      void (*&amp;fn2)(void *,int )) {sz = sizeof(*this);classname = &#34;OBJECT ./object.h&#34;;fn1 = oodb.sub.-- staticCopySelf;fn2 = oodb.sub.-- staticReCopySelf;return((void *)this);} ;public:void persist(const char *db.sub.-- key=0,int flag=0, void*original.sub.-- ptr=0,   void *pointer.sub.-- pos=0,int cnt=0) {int sz; char *classname; void (*fn1)(void *);(*fn2)(void *,int));void *real.sub.-- obj = ((OBJECT *)this)-&gt;oodb.sub.-- GetRealObj(sz,classname,fn1,fn2);int rel.sub.-- pos = (char *)this - (char *)real.sub.-- obj;if (|flag)MakeObjectPersistent(db.sub.-- key,classname,real.sub.-- obj,sz,rel.sub.-- pos,fn1,fn2);else xor.sub.-- pointer.sub.-- class(classname,original.sub.-- ptr,real.sub.-- obj,pointer.sub.-- pos,sz,rel.sub.-- pos,fn1,fn2,cnt);} ;};__________________________________________________________________________ 
    
     
                                           TABLE 3__________________________________________________________________________#include &lt;stdio.h&gt;#include &lt;string.h&gt;#include &#34;opnames.h&#34;#include &#34;tokcodes.h&#34;#include &#34;ccpp.h&#34;#include &#34;symdecl.h&#34;#include &#34;oodb.sub.-- names.h&#34;extern FILE *cout,*cerr;extern char *string.sub.-- save( );extern NAME &#34;GenSym.sub.-- Id( ),*GenSym.sub.-- FuncName( );extern SYMDECL *new.sub.-- yacc.sub.-- tmp( );extern TAGDECL *Tags  !;extern int TagsTop;extern SYMDECL *Xlast.sub.-- Member.sub.-- Added;#define OODB.sub.-- TRAP.sub.-- ON ** /* &#34;OODB.sub.-- trap.sub.--on.sub.-- (this);&#34; */#define OODB.sub.-- FUNC.sub.-- DECL ** /* &#34;extern void *OODB.sub.--trap.sub.-- on.sub.-- (void *);&#34; *//*#define DO.sub.-- NOT.sub.-- WRAP.sub.-- TAG(ty) \|(ty == D.sub.-- CLASS.sub.-- TAG ∥ ty == D.sub.--STRUCT.sub.-- TAG)*/#define DO.sub.-- NOT.sub.-- WRAP(member) \(|ISFTN(member) ∥ \IS.sub.-- FRIEND(member) ∥ IS.sub.-- PURE.sub.-- VIRTUAL(member)∥ \IS.sub.-- STATIC(member) ∥ \fnCTOR(member) ∥ fnDTOR(member))#define IS.sub.-- WRAPPABLE(member) \(|(IS.sub.-- STATIC(member) ∥ fnCTOR(member) ∥ fnDTOR(member)))#define OPERATOR.sub.-- EQ(mem) (fnOPER(mem) &amp;&amp; strcmp(VARNAME(mem),OP.sub.-- EQ) == 0)NAME *Wrapper.sub.-- Baseclass.sub.-- Namep = NULL;SYMDECL *find.sub.-- member( );NAME *change.sub.-- fn.sub.-- name(name)char *name;char buf 1028!;sprintf(buf,&#34;%s%s&#34;,name,&#34;.sub.-- OOdbFn.sub.-- &#34;);return(GenSym.sub.-- Id(buf));}NAME *change.sub.-- conv.sub.-- fn.sub.-- name(func)SYMDECL *func;{static int count = 0;char buf 256!;int i;i = SYMDECL.sub.-- CONV.sub.-- COUNT(func);if (i == 0) {i = ++count;__________________________________________________________________________ 
    
     
                       TABLE 4______________________________________SYMDECL.sub.-- CONV.sub.-- COUNT(func) = i;sprintf(buf,&#34;operator.sub.-- conv.sub.-- %d.sub.-- &#34;,i);return(GenSym.sub.-- Id(buf));}NAME *change.sub.-- operator.sub.-- fn.sub.-- name(name)char *name;{NAME *np;char *new.sub.-- name;int i,l,len,c;char buf 128!,buf1 128!;if (substring(name, &#34;operator&#34;) == 0)dprintf(&#34;error: change.sub.-- operator.sub.-- fn.sub.-- name\n&#34;);for (i = 0,1 = 8; *(name + 1) |= `\0`; ++i, ++;) |c = *(name+1);switch(c) {case `+`: *(buf+i) = `P`;break;case `-`: *(buf+i) = `M`;break;case `*`: *(buf+i) = `m`;break;case `/`: *(buf+i) = `D`;break;case ` `: *(buf+i) = `X`;break;case `&amp;`: *(buf+i) = `A`;break;case `|`: *(buf+i) = `O`;break;case `˜`: *(buf+i) = `C`;break;case `|`: *(buf+i) = `N`;break;case `=`: *(buf+i) = `E`;break;case `&lt;`: *(buf+i) = `L`;break;case `&gt;`: *(buf+i) = `G`;break;case ` `: ++1;while (*(name+1) |= `\0`) (*(buf+i) = *(name+1);         ++i;++1;)--1,--i;break;case `{`: *(buf+i) = `i`;++1,break;case `(`: *(buf+i) = `f`;++1,break;default : dprintf(&#34;unknown char in operator %c\b&#34;,c);break;}}*(buf+i) = `\0`;new.sub.-- name = (char *)get.sub.-- memory(strlen(buf)+8+1);sprintf(buf1,&#34;operator.sub.-- %s&#34;,buf);np = GenSym.sub.-- Id(buf1);return(np);}modify.sub.-- func.sub.-- name(func)SYMDECL *func;{NAME *np:if (fnOPER(func))SYMDECL.sub.-- NAME(func) =change.sub.-- operator.sub.-- fn.sub.-- name(VARNAME(func));else if (fnCONV(func))SYMDECL.sub.-- NAME(func) = change.sub.-- conv.sub.-- fn.sub.-- name(func);else SYNDECL.sub.-- NAME(func) =change.sub.-- fn.sub.-- name(VARNAME(func));}copy.sub.-- function.sub.-- args(nfunc,func)SYMDECL *nfunc, *func;______________________________________ 
    
     
                                           TABLE 5__________________________________________________________________________NAME *np;SYMDECL *args,*Args,*Args1,*new.sub.-- arg;FUNCREC *funcrec;int count;char buf 2048!;buf 0! = `\0`;args = FUNCTION.sub.-- ARGS(nfunc);for (Args = Args1 = NULL,count = 0; args |= NULL; args = SYMDECL.sub.--NEXT(args)) {springf(buf,&#34;ooArg%d&#34;,count++);np = GenSym.sub.-- Id(buf);ALLOCATE.sub.-- SYMDECL(new.sub.-- arg);*new.sub.-- arg = *args;SYMDECL.sub.-- NAME(new.sub.-- arg) = np;SYMDECL.sub.-- NEXT(new.sub.-- arg) = NULL;if (Args == NULL) Args = new.sub.-- arg;else SYMDECL.sub.-- NEXT(Args1) = new.sub.-- arg;Args1 = new.sub.-- arg;}ALLOCATE.sub.-- FUNCREC(funcrec);*funcrec = *SYMDECL.sub.-- FUNCINFO(func);SYMDECL.sub.-- FUNCINFO(nfunc) = funcrec;FUNCREC.sub.-- PROTOARGS(funcrec) = Args;}xwrapper.sub.-- func.sub.-- code(nfunc,funcell,tag)SYMDECL *nfunc;char (funcall;TAGDECL *tag;{SYMDECL *args;int count,d;char buf 2048!,buf1 2048!,*ret;char buf2 512!;buf 0! = `\0`;args = FUNCTION.sub.-- ARGS(nfunc);for (count = 0; args |= NULL; args = SYMDECL.sub.-- NEXT(args)) {if (count++ &gt; 0) strcat(buf,&#34;,&#34;);strcat(buf,VARNAME(args));}d = NEXT.sub.-- DTYPE(SYMDECL.sub.-- DTYPE(nfunc));if (FIRST.sub.-- DTYPE(d) == D.sub.-- NULL &amp;&amp;(SYMDECL.sub.-- TYPE(nfunc) == D.sub.-- VOID ∥SYMDECL.sub.-- TYPE(nfunc) == D.sub.-- NO.sub.-- TYPE))ret =&#34; &#34;;else ret = &#34;return&#34;;*buf2 = `\0`;sprintf(buf1,&#34;{%s%s(%s(%s));}&#34;,OODB.sub.-- TRAP.sub.-- ON.sub.-- CODE(buf2,tag),ret,funcall,buf);FUNCTION.sub.-- CODE(nfunc) = string.sub.-- save(buf1);}SYMDECL *xwrap.sub.-- func(func,tag)SYMDECL *func;TAGDECL *tag;{SYMDECL *nfunc;ALLOCATE.sub.-- SYMDECL(nfunc);*nfunc = *func;copy.sub.-- function.sub.-- args(nfunc,func);modify.sub.-- func.sub.-- name(func);__________________________________________________________________________ 
    
     
                                           TABLE 6__________________________________________________________________________/* generate function code for inline member functions */if (FUNCTION.sub.-- DEFINED(func))xwrapper.sub.-- func.sub.-- code(nfunc,VARNAME(func),tag);/* existing member func gets changed,and its original duplicate nfunc is inserted */if (fnCONV(func)) {SYMDECL.sub.-- FNTYPE(func) = 0;SYMDECL.sub.-- CONV.sub.-- COUNT(nfunc) = SYMDECL.sub.-- CONV.sub.--COUNT(func); }SYMDECL.sub.-- VIRTUAL(func) = 0;return(nfunc);is.sub.-- cp.sub.-- constructor(mem,tag)SYMDECL *mem;TAGDECL *tag;{int arity;unsigned int dtype;SYMDECL *args;if (SYMDECL.sub.-- NAME(mem) |= TAGDECL.sub.-- NAME(tag)) return(0);if (FUNCTION.sub.-- ARITY(mem) |= 1) return(0);args = FUNCTION.sub.-- ARGS (mem);dtype = SYMDECL.sub.-- DTYPE(args);if (C.sub.-- ISREF(dtype) &amp;&amp; NEXT.sub.-- DTYPE(dtype) == 0) {int type = SYMDECL.sub.-- TYPE(args);TAGDECL *tag1;if (type == D.sub.-- TYPEREF) {SYMDECL *typedef.sub.-- sym = SYMDECL.sub.-- TYPEDEFNAME(args);if CLASS.sub.-- STRUCT.sub.-- TYPE(SYMDECL.sub.-- TYPE(typedef.sub.--sym)))tag1 = SYMDECL.sub.-- TAG(typedef.sub.-- sym);else retunr(0); }else if (CLASS.sub.-- STRUCT.sub.-- TYPE(type)) tag1 = SYMDECL.sub.--TAG(args);else return(0);if (tag == tag1) return(1);else return(0); }return(0);}create.sub.-- operator.sub.-- eq(tag)TAGDECL *tag;{SYMDECL *fn,*arg;char buf 2048!,buf1 2048!;ALLOCATE.sub.-- SYMDECL(arg);SYMDECL.sub.-- NAME(arg) = GenSym.sub.-- Id(&#34;arg&#34;);SYMDECL.sub.-- TYPE(arg) = D.sub.-- TYPEREF;SYMDECL.sub.-- TYPEDEFNAME(arg) = TAGDECL.sub.-- TAGTYPEDEF(tag);SYMDECL.sub.-- DTYPE(arg) = D.sub.-- REF;SYMDECL.sub.-- TYPEQ(arg) = D.sub.-- CONST;ALLOCATE.sub.-- SYMDECL(fn);SYMDECL.sub.-- NAME(fn) = GenSym.sub.-- Id(OP.sub.-- EQ);SYMDECL.sub.-- FNTYPE(fn) = FNTYPE.sub.-- OPER;SYMDECL.sub.-- TYPE(fn) = D.sub.-- TYPEREF;SYMDECL.sub.-- TYPEDEFNAME(fn) = TAGDECL.sub.-- TAGTYPEDEF(tag);SYMDECL.sub.-- ACCESS(fn) = D.sub.-- PUBLIC;make.sub.-- fnrec(fn,arg,1);SYMDECL.sub.-- DTYPE(fn) = INSERT.sub.-- DTYPE(D.sub.-- FTN,D.sub.--REF);OODB.sub.-- ARG.sub.-- TRAP.sub.-- ON.sub.-- CODE(&#34;arg&#34;,TAGNAME(tag),buf1);__________________________________________________________________________ 
    
     
                       TABLE 7______________________________________sprintf(buf,&#34;{\n\%s\n\{int i;char *ptr = (char *)this,*ptr1 = (char *)&amp;arg;\n.backslash.for (i = 0; i &lt; sizeof(*this); ++i) *ptr++ = *ptr1++;}\n.backslash.return(*this);}&#34;,buf1);symdecl.sub.-- INITCODE(fn) = string.sub.-- save(buf);xaddend.sub.-- member(tag,fn);create.sub.-- cp.sub.-- constructor(tag)TAGDECL *tag;SYMDECL *fn,*arg;char buf 2048!,buf1 2048!;create.sub.-- default.sub.-- constructor(tag);ALLOCATE.sub.-- SYMDECL(fn);SYMDECL.sub.-- NAME(fn) = GenSym.sub.-- Id(TAGNAME(tag));SYMDECL.sub.-- FNTYPE(fn) = FNTYPE.sub.-- CTOR;SYMDECL.sub.-- TYPE(fn) = D.sub.-- NO.sub.-- TYPE;SYMDECL.sub.-- ACCESS(fn) = D.sub.-- PUBLIC;ALLOCATE.sub.-- SYMDECL(arg);SYMDECL.sub.-- NAME(arg) = GenSym.sub.-- Id(&#34;arg&#34;);SYMDECL.sub.-- TYPE(arg) = D.sub.-- TYPEREF;SYMDECL.sub.-- TYPEDEFNAME(arg) =TAGDECL.sub.-- TAGTYPEDEF(tag);SYMDECL.sub.-- DTYPE(arg) = D.sub.-- REF;SYMDECL.sub.-- TYPEQ(arg) = D.sub.-- CONST;make.sub.-- fnrec(fn,arg,1);OODB.sub.-- ARG.sub.-- TRAP.sub.-- ON.sub.-- CODE(&#34;arg&#34;,TAGNAME(tag),buf1);sprintf(buf,&#34;{\n\%s\n\{int i;char *ptr = (char *)this,*ptr1 = (char *)&amp;arg;\n.backslash.for (i = 0; i &lt; sizeof(*this); ++i) *ptr++ = *ptr1++;}}\n&#34;,buf1);#if 0sprintf(buf,&#34;\n\{%s}&#34;,buf1);#endifSYMDECL.sub.-- INITCODE(fn) = string.sub.-- save(buf);xaddend.sub.-- member(tag,fn);}xwrapper(tag)TAGDECL *tag;{SYMDECL *nmem;SYMDECL *members = TAGDECL.sub.-- MEMBERLIST(tag);int ty = TAGDECL.sub.-- TYPE(tag);int op.sub.-- flag,cp.sub.-- flag;______________________________________ 
    
     
                                           TABLE 8__________________________________________________________________________if (oodb.sub.-- Nwrapped(TAGNAME(tag))} return(0);if (DO.sub.-- NOT.sub.-- WRAP.sub.-- TAG(ty)) return(0);Xlast.sub.-- Member.sub.-- Added = NULL;Add.sub.-- Wrapper.sub.-- Baseclass(tag);op.sub.-- flag = cp.sub.-- flag = 0;for (; members |= NULL; members = SYMDECL.sub.-- NEXT(members))|if (IS.sub.-- MEMBER.sub.-- FUNCTION(members) &amp;&amp; IS.sub.-- FRIEND(members)) {xwrap.sub.-- friend.sub.-- member.sub.-- func(members);continue; }else if (DO.sub.-- NOT.sub.-- WRAP(members)) {if (SYMDECL.sub.-- NAME(members) == TAGDECL.sub.-- NAME(tag) &amp;&amp; fnCTOR(members) &amp;&amp; is.sub.-- cp.sub.-- constructor(members, tag))cp.sub.-- flag = 1;continue; }else if (OPERATOR.sub.-- EQ(members))op.sub.-- flag = 1;nmem = xwrap.sub.-- func(members,tag);SYMDECL.sub.-- NEXT(nmem) = SYMDECL.sub.-- NEXT(members);SYMDECL.sub.-- NEXT(members) = nmem;members = nmem; }if (|op.sub.-- flag) create.sub.-- operator.sub.-- eq(tag);if (|cp.sub.-- flag) create.sub.-- cp.sub.-- constructor(tag);xwrap.sub.-- friend.sub.-- member.sub.-- func(func)SYMDECL *func;{TAGDECL *tag = ENV(func); /* get class of func */SYMDECL *member;member = find.sub.-- member(func,tag);if (member == NULL) dprintf(&#34;error: xwrap.sub.-- member.sub.-- func&#34;);if (IS.sub.-- WRAPPABLE(member)) modify.sub.-- func.sub.-- name(func);}/*called for out-of-class member function definitions */SYMDECL *xwrapper.sub.-- change.sub.-- functioon.sub.-- name(func)SYMDECL *func;{SYMDECL *member;if (|IS.sub.-- MEMBER.sub.-- FUNCTION (func)) return(NULL);if (DO.sub.-- NOT.sub.-- WRAP(func)) return(MULL);/* find real member - and check whether its name needs to be changed */member = find.sub.-- member(func,SYMDECL.sub.-- ENV(func));if (member == NULL) {dprintf(*error:member not found: xwrapper.sub.-- change.sub.-- function.sub.-- name&#34;);return(NULL); }if (DO.sub.-- NOT.sub.-- WRAP(member)) return(NULL);SYMDECL.sub.-- FNTYPE(func) = SYMDECL.sub.-- FNTYPE(member);SYMDECL.sub.-- CONV.sub.-- COUNT(func) = SYMDECL.sub.-- CONV.sub.--COUNT(member);modify.sub.-- func.sub.-- name(func);if (fnCONV(func))SYMDECL.sub.-- FNTYPE(func) = 0;return(member); /* code for generated member if done in__________________________________________________________________________ 
    
     
                       TABLE 9______________________________________xwrapper.sub.-- function.sub.-- code */______________________________________xwrapper function.sub.-- code (mem.sub.-- func, func)SYMDECL T.sub.mem--func,*func;SYMDECL *nfunc;if {lmem.sub.-- func} return(0);LOCATE.sub.-- SYMDECL(nfunc);nfunc = *func;SYMDECL.sub.-- NAME(nfunc) = SYMDECL.sub.-- NAME(mem.sub.-- func);SYMDECL.sub.-- FNTYPE(nfunc) = SYMDECL.sub.-- FNTYPE(mem.sub.-- func);copy.sub.-- function.sub.-- args(nfunc,func);xwrapper.sub.-- func.sub.-- code(nfunc,VARNAME(func),SYMDECL.sub.--ENV(func));print.sub.-- symbol(nfunc);/* can free up nfunc */}SYMDECL *find.sub.-- member(func,tag)SYMDECL *func;TAGDECL *tag;{SYMDECL *memlist = TAGDECL.sub.-- MEMBERLIST(tag);NAME *np;np = SYMDECL.sub.-- NAME(func);for (; memlist 1= NULL; memlist = SYMDECL.sub.-- NEXT(memlist)) { if (SYMDECL.sub.-- NAME(memlist) == np &amp;&amp; ISFTN(memlist) &amp;&amp; same.sub.-- func.sub.-- signature(func,memlist)) return(memlist);}return(NULL);cm.sub.-- Wrapper.sub.-- Baseclass()NAME *np;TAGDECL *tag;extern SYMDECL *make.sub.-- class.sub.-- typedef();np = GenSym.sub.-- Id(WRAPPER.sub.-- BASECLASS.sub.-- NAME);Wrapper.sub.-- Baseclass.sub.-- Namep = np;ALLOCATE.sub.-- TAGDECL(tag);TAGDECL.sub.-- NAME(tag) = np;TAGDECL.sub.-- TYPE(tag) = D.sub.-- CLASS.sub.-- TAG;TAGDECL.sub.-- TAGTYPEDEF(tag) = make.sub.-- class.sub.-- typedef(tag);NAME.sub.-- TAGINFO(np) = tag);}Add.sub.-- Wrapper.sub.-- Baseclass(tag)TAGDECL *tag;{BASECLASS *base;ALLOCATE.sub.-- BASECLASS(base);if (Wrapper.sub.-- Baseclass.sub.-- Namep == NULL) Form.sub.-- Wrapper.sub.-- Baseclass();BASECLASS.sub.-- NAME(base) = Wrapper.sub.-- Baseclass.sub.-- Namep;BASECLASS.sub.-- ACCESS(base) = D.sub.-- PUBLIC;BASECLASS.sub.-- VIRTUAL(base) = 1;______________________________________ 
    
     
                       TABLE 10______________________________________BASECLASS.sub.-- NEXT(base) = TAGDECL.sub.-- BASELIST(tag);TAGDECL.sub.-- BASELIST(tag) = base;OODB.sub.-- TRAP.sub.-- ON.sub.-- CODE(buf,tag)char *buf;TAGDECL *tag;{char buf1(256);print.sub.-- tagname(tag,buf1);sprintf(buf,*if(%s == 1) (\n\ int sz;char *classname;void (*fn1) (void *),(*fn2) (void*,int);\n\ %s-&gt;%s(((%s *)this)-&gt;%s(sz,classname,fn1,fn2));%s(0);}*, WRAPPER.sub.-- TRAP.sub.-- FLAG.sub.-- OODB.sub.-- INSTANCE,TRAP.sub.--ON, buf1,GET.sub.-- REAL.sub.-- OBJ, WRAPPER.sub.-- SET.sub.-- TRAP);}OODB.sub.-- ARG.sub.-- TRAP.sub.-- ON.sub.-- CODE(name,type,buf)char *name,*type,*buf;{sprintf(buf,*if(%s,%s == 1) (\n\ int sz,char *classname;void (*fn1) (void *),(*fn2) (void*,int);\n\ %s-&gt;%s(((%s &amp;)%s),%s(sz,classname,fn1,fn2));\n\ ((%s &amp;)%s),%s(0);}*,name,WRAPPER.sub.-- TRAP.sub.-- FLAG,OODB.sub.-- INSTANCE,TRAP,ON,type,name,GET.sub.-- REAL.sub.-- OBJ,type,name,WRAPPER.sub.-- SET.sub.--TRAP);}______________________________________