/************************************************************************** * PROJECT: DEMETER Version 5.0 * MODULE: GENERATION * FILE: gen_classes.C * SYSTEM: C++ AT&T version 2.0 on sun, UNIX 4.3 BSD *-------------------------------------------------------------------------- * COPYRIGHT (c) 1990 Northeastern University * Prof. Karl J. Lieberherr *-------------------------------------------------------------------------- * AUTHOR: Walter Hursch * * DATE: December 10, 1990 * REVISED: April 8, 1991 * - move #include "USER/user.h" to user.h after * classes. * - generate: const B *get_x() * - generate default pointers to NULL * September 3, 1991 * - remove const X *get_y() * - add const member functions * March 17, 1992 * Added class Text * May 18, 1992 * remove inclusion of D__token.h * July 22, 1992 * Add const member functions * July 23, 1992 * Generate virtual destructor for alt. classes * November 5, 1992 * Allow for component and external terms * Fri Jul 9 11:28:56 1993 * Removed member function make_instance * * $Log: gen_classes.C,v $ * Revision 5.4.1.1 1994/02/28 16:35:13 huersch * *** empty log message *** * * Revision 5.4 1994/02/28 16:35:10 huersch * *** empty log message *** * * Revision 5.3.1.1 1994/01/26 19:05:42 huersch * No changes. * * Revision 5.3 1994/01/26 19:05:41 huersch * *** empty log message *** * * Revision 5.2.1.1 1994/01/24 16:15:56 huersch * No changes. * * Revision 5.2 1994/01/24 16:15:49 huersch * *** empty log message *** * * Revision 5.1.1.1 1993/11/15 15:17:39 demeter * *** empty log message *** * * Revision 5.1 1993/11/15 15:17:38 demeter * *** empty log message *** * * Revision 5.0.1.9 1993/10/06 22:24:39 huersch * Unified SI and MI version into one run-exec file * #ifdef MI ==> if (MIFLAG) * * Revision 5.0.1.8 1993/10/06 19:17:52 huersch * Undid changes for templates. * Finished integration of *private* and *read-only*. * *-------------------------------------------------------------------------- * DESCRIPTION: * Gen_classes generates data-dictionary dependent part of the file * interface.h in the directory given by char *path. Interface.h cons- * ists of a cd dependent part which is generated here and an indepen- * dent part called terminals.h that is later copied to the bottom of * the generated file from directory DEM-gen-concat. * * **************************************************************************/ /************************************************************************** Class dictionary used (Intermediate notation) ;;; produced by extract-cd '(I-P1|O-P1)' ;;; produced by extract-cd 'O-P1' ; : O-P1: intermediate notation ;;; O-P1=I-P2 Demeter_in = Input. Input : Cd_graph *common*. Cd_graph = < adjacencies > Nlist(Adjacency) ["*terminal_sets*" Comma_list(Vertex) "."]. Adjacency = < source > Vertex < ns > Neighbors ["*inherits_from*" Comma_list(Term)] "." . Neighbors : Intermediate_ns *common*. Intermediate_ns : Repetit | Non_repetit *common*. Non_repetit : Instantiable | Abstract *common* List(Int_part). Instantiable = "instantiable=". Repetit = "repetition=" Term [ Non_empty]. Non_empty = "*non_empty*". Abstract = "abstract=". Int_part : Required_int_part | Optional_int_part *common* Labeled. Required_int_part = "*required*". Optional_int_part = "*optional*". Vertex = < vertex_name > Ident . Opt_labeled_term : Labeled *common* Term. Labeled = "<" < label_name > Ident ">" . ;; ;; 11/5/92 Update term to contain component and external terms ;; Term : Normal | CppTerm *common* Vertex TermRef ["(" Comma_list(Term) ")" ]. CppTerm = "$" . Normal = . TermRef : LocalRef | ModuleRef. ModuleRef : CompRef | LibRef *common* Ident. LocalRef = . CompRef = "@". LibRef = "@@". ; parameterized classes List(S) ~ {S}. Nlist(S) ~ S {S}. Comma_list(S) ~ S {"," S}. ====================================================================*/ #include "generate.h" #include #include #include #include /*------------------------------------------------------------------------- * Method: void gen_classes( char* ) * * Takes the method down the CD graph to Adjacency_Nlist. *-----------------------------------------------------------------------*/ /* * Demeter_in = Input. */ void Demeter_in::gen_classes( char* filename, char* top, char* TOP ) { input -> gen_classes( filename, top, TOP ); } /* * Input : Cd_graph *common*. */ void Input::gen_classes( char*, char* , char* ) { } /* * Cd_graph = < adjacencies > Nlist(Adjacency) * ["*terminal_sets*" Comma_list(Vertex) "."]. */ void Cd_graph::gen_classes( char* filename, char* top, char* TOP ) { adjacencies -> gen_classes( filename, top, TOP ); } /* * Cd_graph = < adjacencies > Nlist(Adjacency) * Adjacency = < source > Vertex < ns > Neighbors * ["*inherits_from*" Comma_list(Term)] "." . */ void Adjacency_Nlist::gen_classes( char* filename, char* top, char* TOP) { Adjacency_list_iterator next_arg1( *this ); Adjacency_list_iterator next_arg2( *this ); Adjacency_ each_arg = next_arg1(); ofstream outFile( filename, ios::out ); if (!outFile) { cerr << "cannot open " << filename << " for output\n"; exit( -1 ); } outFile << "/*-----------------------------------" << "------------------------------------\n" << " * DEMETER System Version 5.0\n" << " * Copyright (c) 1993 Northeastern University\n" << " *-----------------------------------" << "-------------------------------------\n" << " *\n" << " * GENERATED FILE -- DO NOT CHANGE !!\n" << " */\n\n"; // write includes outFile << "#ifndef " << TOP << "_H \n" << "#define " << TOP << "_H \n" << "#include \"demeter.h\"\n" << "#include \"rep-macro.h\"\n" // not needed for templates << "#include \n" << "#include \n" << "#include \n" << "#include \n\n"; /* write class names because Adjacency_Nlist is always non-empty, the following do-while-loop is allowed. */ do { outFile << "class " << each_arg -> get_class_name() << ";\n"; } while ( each_arg = next_arg1() ); // write built-in classes outFile << "class DemNumber;\n" << "class DemReal;\n" << "class DemIdent;\n" << "class DemString;\n" << "class DemText;\n\n" << "#include \"global.h\"\n\n"; // send method 'gen_classes' to each adjacency while ( each_arg = next_arg2() ) { each_arg -> gen_classes( this, outFile ); } outFile << "\n#endif /* " << TOP << "_H */ \n"; // Close output file outFile.close(); } /*------------------------------------------------------------------------- * Method: void gen_classes( Adjacency_Nlist*, ofstream& ) * Generate class defintion for each Adjacency in correct topological order * (Cun Xiao) *-----------------------------------------------------------------------*/ /* * Adjacency = < source > Vertex < ns > Neighbors * ["*inherits_from*" Comma_list(Term) "." . */ void Adjacency::gen_classes( Adjacency_Nlist* adj_Nlist, ofstream& outFile ) { DBG( cout << "IN Adjacency::gen_classes" << endl ); static Adjacency_Nlist* generated = new Adjacency_Nlist(); Term_Comma_list* inherit_list = this -> get_inherits_from(); Adjacency_list_iterator next_Adj( *generated ); Adjacency_ each_Adj; if ( inherit_list ) { Term_list_iterator next_Term( *inherit_list ); Term_ each_Term; while ( each_Term = next_Term() ) { Adjacency_list_iterator next_Adj2( *adj_Nlist ); Adjacency_ each_Adj2; while ( each_Adj2 = next_Adj2() ) if ( each_Term -> get_vertex() -> g_equal( each_Adj2 -> get_source()) ) each_Adj2 -> gen_classes ( adj_Nlist, outFile ); } } if ( generated -> list_length() > 0 ) while ( each_Adj = next_Adj() ) if ( each_Adj -> g_equal( this ) ) return; generated -> append( this ); ns -> gen_classes( outFile, this ); DBG( cout << "OUT Adjacency::gen_classes\n" << endl ); } /*------------------------------------------------------------------------- * Method: void gen_classes( ofstream&, Adjacency* ) * * In Instantiable, Abstract and Repetit the main parts of the program are * done. *-----------------------------------------------------------------------*/ /* * Neighbors : Intermediate_ns *common*. */ void Neighbors::gen_classes( ofstream&, Adjacency* ) { } /* * Intermediate_ns : Repetit | Non_repetit *common*. */ void Intermediate_ns::gen_classes( ofstream&, Adjacency* ) { } /* * Non_repetit : Instantiable | Abstract *common* List(Int_part). */ void Non_repetit::gen_classes( ofstream&, Adjacency* ) { } /* * Instantiable = "instantiable=". */ void Instantiable::gen_classes( ofstream& outFile, Adjacency* cur_adj ) { DBG( cout << "IN Instantiable::gen_classes" << endl ); char include_name[256]; char* name = cur_adj -> get_class_name(); Term_Comma_list* inherit_list = cur_adj -> get_inherits_from(); outFile << "class " << name; if ( inherit_list != NULL ) { outFile << " :"; inherit_list -> gen_derivation_list( outFile ); } outFile << " {\n" << "private:\n"; Non_repetit::gen_private_data_members( outFile ); outFile << "public:\n"; // generate constructor definition Non_repetit::gen_constructor_def( outFile, name ); // generate regular destructor for construction classes outFile << " ~" << name << "();\n"; Non_repetit::gen_accessor( outFile ); if ( MIFLAG ) { Non_repetit::gen_castdown_def( outFile, name ); } outFile << " const char* get_type() const { return( type ); }\n" << " static const char* get_formal_type() " << "{ return type; }\n" << " void set_data_member( int, Universal* );\n" << " Universal* get_data_member( int ) const;\n" << " int number_of_parts() const;\n" << " int number_of_imm_parts() const;\n\n" << " void DEM_abstract() { }\n" << " void pp( ostream& = cout ) const;\n"; strcpy( include_name, name ); strcat( include_name, ".h" ); outFile << "#include \"" << include_name << "\"\n" << "};\n\n"; DBG( cout << "OUT Instantiable::gen_classes" << endl ); } /* * Abstract = "abstract=". */ void Abstract::gen_classes( ofstream& outFile, Adjacency* cur_adj ) { DBG( cout << "IN Abstract::gen_classes" << endl ); char include_name[256]; char* name = cur_adj -> get_class_name(); Term_Comma_list* inherit_list = cur_adj -> get_inherits_from(); outFile << "class " << name; if ( inherit_list != NULL ) { outFile << " : "; inherit_list -> gen_derivation_list( outFile ); } outFile << " {\n" << "private:\n"; Non_repetit::gen_private_data_members( outFile ); outFile << "public:\n"; // generate constructor Non_repetit::gen_constructor_def( outFile, name ); // generate virtual destructor for abstract classes outFile << " virtual ~" << name << "();\n"; Non_repetit::gen_accessor( outFile ); if ( MIFLAG ) { Non_repetit::gen_castdown_def( outFile, name ); } outFile << " const char* get_type() const { return( type ); }\n" << " static const char* get_formal_type() " << "{ return type; }\n" << " virtual void set_data_member( int, Universal* );\n" << " virtual Universal* get_data_member( int ) const;\n" << " virtual int number_of_parts() const;\n" << " virtual int number_of_imm_parts() const;\n\n" << " virtual void DEM_abstract() = 0;\n" << " virtual void pp( ostream& = cout ) const;\n"; strcpy( include_name, name ); strcat( include_name, ".h" ); outFile << "#include \"" << include_name << "\"\n" << "};\n\n"; DBG( cout << "OUT Abstract::gen_classes" << endl ); } /* * Repetit = "repetition=" Term [ Non_empty]. */ int term_memberfunc( Universal* term1, Universal* term2 ) { return ( ((Universal *)term1) -> g_equal( (Universal *)term2 ) == 1 ); } void Repetit::gen_classes( ofstream& outFile, Adjacency* cur_adj ) { DBG( cout << "IN Repetit::gen_classes" << endl ); char include_name[256]; char* name = cur_adj -> get_class_name(); strcpy( include_name, name ); strcat( include_name, ".h" ); char* rep_name = repeated -> get_class_name(); /* templates outFile << "class " << name << " : public " << "D__linked_list<" << rep_name << "> {\n" << "private:\n" << " static const char* type;\n"; outFile << "public:\n"; outFile << " " << name << "( " << rep_name // constructor << "* first ) : \n" << " D__linked_list<" << rep_name << ">( first ) { \/\* empty \*\/ };\n"; outFile << " " << name << "( ) { \/\* empty \*\/ };\n"; // empty constructor outFile << " " << name << "( " << name // copy constructor << "& other ) : \n" << " D__linked_list<" << rep_name << ">( other ) { \/\* empty \*\/ };\n"; // destructor, not defined. outFile << " D__linked_list<" << rep_name << ">* new_likeThis() " << "{ return new " << name << "( *this ); }\n\n"; outFile << " const char* get_type() const { return ( type ); }\n" << " static const char* get_formal_type() " << "{ return type; }\n" << " void pp( ostream& = cout ) const;\n"; outFile << "#include \"" << include_name << "\"\n" << "};\n\n"; */ /* BEGIN non-templates */ static Term_Comma_list *already_generated = new Term_Comma_list(); if ( !already_generated -> member( repeated, term_memberfunc ) ) { outFile << "typedef " << rep_name << "* " << rep_name << "_;\n" << "declare(list," << rep_name << "_);\n\n"; already_generated -> append( repeated ); } outFile << "class " << name << " : public " << rep_name << "_list_ {\n" << "private:\n" << " static const char* type;\n"; outFile << "public:\n" << " " << name << "( " << rep_name << "* first ) : " << rep_name << "_list_( first ) { /* empty */ };\n" << " " << name << "() { /* empty */ };\n" // empty constructor << " ~" << name << "() { /* empty */ };\n"; // empty destructor /* END non-templates */ outFile << " const char* get_type() const { return ( type ); }\n" << " static const char* get_formal_type() " << "{ return type; }\n" << " void pp( ostream& = cout ) const;\n"; outFile << "#include \"" << include_name << "\"\n" << "};\n\n"; DBG( cout << "OUT Repetit::gen_classes" << endl;) } /*------------------------------------------------------------------------- * Method: void gen_derivation_list( ofstream& outFile ) * * Generates the class derivation list, a (possibly) comma-separated list * of one or more base classes. *-----------------------------------------------------------------------*/ /* * term-Comma_list ~ term { "," term } . */ // For multiple inheritance: inherit virtual only void Term_Comma_list::gen_derivation_list( ofstream& outFile ) { DBG( cout << "IN gen_derivation_list" << endl ); Term_list_iterator next_arg( *this ); Term_ each_arg = next_arg(); if ( MIFLAG ) { // multiple inheritance: generate virtual base classes only outFile << " virtual public " << each_arg -> get_class_name(); while ( each_arg = next_arg() ) { outFile << ", virtual public " << each_arg -> get_class_name(); } } else { // single inheritance outFile << " public " << each_arg -> get_class_name(); // Note: the following is not necessary for single inheritance while ( each_arg = next_arg() ) { outFile << ", public " << each_arg -> get_class_name(); } } DBG( cout << "OUT gen_derivation_list" << endl ); } /*------------------------------------------------------------------------- * Method: void gen_castdown_def( ofstream&, char* ) * * Generates all castdown functions of a class 'name'. Only used with * multiple inheritance! * *-----------------------------------------------------------------------*/ void Non_repetit::gen_castdown_def( ofstream& outFile, char* name ) { DBG( cout << "IN gen_castdown_def" << endl ); outFile << " static " << name << "* castdown(Universal* u) const\n" << "\t{ return (" << name << "*) " << "(u ? u->_safe_castdown(get_formal_type()) : 0); }" << endl; outFile << " static const " << name << "* castdown(const Universal* u) const\n" << "\t{ return (const " << name << "*) " << "(u ? u->_safe_castdown(get_formal_type()) : 0); }" << endl; outFile << " virtual void* _castdown(const char*) const;" << endl; DBG( cout << "OUT gen_castdown_def" << endl;) } /*------------------------------------------------------------------------- * Method: void gen_private_data_members( ofstream& ) * * Generates the private data member declaration part of the class defini- * tion. *-----------------------------------------------------------------------*/ /* * Non_repetit : Instantiable | Abstract *common* List(Int_part). */ void Non_repetit::gen_private_data_members( ofstream& outFile ) { DBG( cout << "IN Non_repetit::gen_private_data_members" << endl ); intermed_ns -> gen_private_data_members( outFile ); DBG( cout << "OUT Non_repetit::gen_private_data_members" << endl ); } /* * Non_repetit : Instantiable | Abstract *common* List(Int_part). * Int_part : Required_int_part | Optional_int_part * *common* Labeled. */ void Int_part_List::gen_private_data_members( ofstream& outFile ) { DBG( cout << "IN Int_part_list::gen_private_data_members" << endl ); Int_part_list_iterator next_Part( *this ); Int_part_ each_Part; while ( each_Part = next_Part() ) { outFile << " "; if ( each_Part -> get_staticspec() != NULL ) { outFile << "static "; } outFile << each_Part -> get_class_name() << each_Part -> get_class_type() << " " << each_Part -> get_var_name() << ";\n"; // generate private reader function if necessary each_Part -> gen_privateReader( outFile ); } outFile << " static const char* type;\n"; DBG( cout << "OUT Int_part_list::gen_private_data_members" << endl ); } /*------------------------------------------------------------------------- * Method: void gen_accessor( ofstream& ) * * Generates all accessor functions of a class: * - get_part() * - set_part() * - rset_part() *-----------------------------------------------------------------------*/ void Non_repetit::gen_accessor( ofstream& outFile ) { intermed_ns -> gen_accessor( outFile ); } void Int_part_List::gen_accessor(ofstream& outFile) // writes the public accessor functions for each part of the current class { Int_part_list_iterator next_Part( *this ); Int_part_ each_Part; int i = 0; while (each_Part = next_Part()) { each_Part -> gen_publicReader( outFile ); // if accessorspec is defined; i.e. part is read-only or private, // no setters are defined. if ( each_Part -> get_accessorspec() == NULL ) { each_Part -> gen_setter( outFile ); each_Part -> gen_rsetter( outFile ); } i++; } if ( i > 0 ) outFile << "\n"; } void Int_part::gen_publicReader(ofstream& outFile) // Readers are public 1) by default 2) if part is specified read-only { if ( accessorspec == NULL || !strcmp( "ReadOnlyAcc", accessorspec -> get_type() ) ) { this -> gen_reader( outFile ); } } void Int_part::gen_privateReader(ofstream& outFile) // Readers are private if part is specified private { if ( accessorspec != NULL && !strcmp( "PrivateAcc", accessorspec->get_type() ) ) { this -> gen_reader( outFile ); } } void Int_part::gen_reader(ofstream& outFile) // write 'Class* get_var();' { outFile << " "; if ( get_staticspec() != NULL ) { outFile << "static "; } outFile << get_class_name() << get_class_type() << " " << "get_" << get_var_name() << "() const { return( " << get_var_name() << " ); }\n"; } void Int_part::gen_setter(ofstream& outFile) // write 'void set_var(Class* new_var) { var = new_var };' { outFile << " "; if ( get_staticspec() != NULL ) { outFile << "static "; } outFile << "void set_" << get_var_name() << "( " << get_class_name() << get_class_type() << " " << "new_" << get_var_name() << " ) " << "{ " << get_var_name() << " = new_" << get_var_name() << "; }\n"; } void Int_part::gen_rsetter(ofstream& outFile) // write 'Class* rset_var(Class*);' { // Note, implementation generated in gen_non_inline.C outFile << " "; if ( get_staticspec() != NULL ) { outFile << "static "; } outFile << get_class_name() << get_class_type() << " " << "rset_" << get_var_name() << "( " << get_class_name() << get_class_type() << " );\n"; } /*------------------------------------------------------------------------- * Method: int part_list_non_empty() *-----------------------------------------------------------------------*/ /* not used anymore: Walter Hursch 1/8/91 */ int Non_repetit::part_list_non_empty() { // Remember: empty returns 0 for an empty list (see 'man predefined'). return ( intermed_ns -> empty() ); } /*------------------------------------------------------------------------- * Method: void gen_constructor_def( ofstream&, char* ) * * Generates constructor of a construction or alternation class. *-----------------------------------------------------------------------*/ int ctorIsDesired( char* classname ) { // check whether a constructor is desired at all. const int MAXPATH = 1024; // We need our own copy since strtok is destructive. // NOCTORLIST globally defined char noCtorList[MAXPATH]; strcpy( noCtorList, NOCTORLIST); char* token; char* delimiters = " ,\t\n\v\r\a\f"; token = strtok( noCtorList, delimiters ); while ( token != NULL ) { if ( strcmp( token, classname ) == NULL ) { // classname found in noCtor list, hence no ctor desired return ( 0 ); } token = strtok( NULL, delimiters ); } // still here, then class is not in noCtorList, // hence constructor is desired. return ( 1 ); } void Non_repetit::gen_constructor_def( ofstream& outFile, char* name ) { if ( ctorIsDesired( name ) ) { intermed_ns -> gen_constructor_def( outFile, name ); } } void Int_part_List::gen_constructor_def( ofstream& outFile, char* name ) // writes constructor of class 'name' to file 'outFile'. { Int_part_list_iterator next_Int_part( *this ); Int_part_ each_Int_part; outFile << " " << name << "("; if ( each_Int_part = next_Int_part() ) { outFile << " " << each_Int_part -> get_class_name() << each_Int_part -> get_class_type() << " = NULL"; while (each_Int_part = next_Int_part()) { outFile << ", " << each_Int_part -> get_class_name() << each_Int_part -> get_class_type() << " = NULL"; } outFile << " "; } outFile << ");\n"; } /*------------------------------------------------------------------------- * Method: char* get_class_name() * * Returns the class name of an adjacency, given either as an object of * class adjacency or an object of class Int_part. * Get_class_name() is used by many other methods. * * Method: char* get_class_type() * * Returns the type associated with the Int_part (pointer or plain) * as a string. *-----------------------------------------------------------------------*/ /* * Adjacency = < source > Vertex < ns > Neighbors * ["*inherits_from*" Comma_list(Term)] "." . */ char* Adjacency::get_class_name() { return ( source -> get_class_name() ); } /* * Int_part : Required_int_part | Optional_int_part * *common* Labeled. */ char* Int_part::get_class_name() { return ( labeled_int_part -> get_class_name() ); } char* Int_part::get_class_type() { return ( labeled_int_part -> get_class_type() ); } /* * Opt_labeled_term : Labeled *common* Term. */ char* Opt_labeled_term::get_class_name() { return ( vertex -> get_class_name() ); } char* Opt_labeled_term::get_class_type() { return ( vertex -> get_class_type() ); } char* Labeled::get_class_name() { return ( Opt_labeled_term::get_class_name() ); } char* Labeled::get_class_type() { return ( Opt_labeled_term::get_class_type() ); } /* * Term : Normal | CppTerm * *common* Vertex * TermRef * ["(" Comma_list(Term) ")" ]. * * Class names are defined by: * * Term Class name Type * * C ==> C pointer * $int ==> int plain * $mytype@comp ==> mytype plain * $mytype@@lib ==> mytype plain * C@comp ==> C@comp pointer * C@@lib ==> C@@lib pointer * * That is, class names are base names for all but component references. */ char* Term::get_class_name() { return ( vertex -> get_class_name() ); } char* Term::get_class_type() { // by default return a pointer type except for CppTerms return ( "*" ); } char* CppTerm::get_class_type() { // C++ standard terms are plain types return ( "" ); } char* Normal::get_class_name() { // return whatever moduleRef appends to basename return ( get_moduleRef() -> get_class_name( Term::get_class_name() ) ); } char* TermRef::get_class_name( char* class_name_base ) { // class name == base, as a default for all LocalRef instances return ( class_name_base ); } char* CompRef::get_class_name( char* class_name_base ) { const int MAXLEN = 256; char* class_name = new char[MAXLEN]; strcpy( class_name, class_name_base ); strcat( class_name, "@" ); strcat( class_name, get_moduleName()->get_val() ); return ( class_name ); } char* LibRef::get_class_name( char* class_name_base ) { const int MAXLEN = 256; char* class_name = new char[MAXLEN]; strcpy( class_name, class_name_base ); strcat( class_name, "@@" ); strcat( class_name, get_moduleName()->get_val() ); return ( class_name ); } /* * Vertex = Ident. */ char* Vertex::get_class_name() { return ( vertex_name->get_val() ); } /*------------------------------------------------------------------------- * Method: char* get_var_name() * * Returns the variable name of a part given as an object of class Int_part. * Get_var_name() is used by many other methods. *-----------------------------------------------------------------------*/ /* * Int_part : Required_int_part | Optional_int_part * *common* Labeled. */ char* Int_part::get_var_name() { return ( labeled_int_part -> get_var_name() ); } /* * Labeled = "<" < label_name > Ident ">" . */ char* Labeled::get_var_name() { return ( label_name -> get_val() ); }