#ifndef parser_h #define parser_h #include #include #include #include #include #include #include "lexer.h" namespace parser { struct lexer_t; enum exceptions_translation { exceptionstranslation_PRESERVE, exceptionstranslation_EXIT, exceptionstranslation_FUDGE }; struct outstream_t /* This contains state that alters how parser nodes are output.*/ { explicit outstream_t( std::ostream& out0); outstream_t( std::ostream& out0, const outstream_t& outstream); /* copies outstream, apart from the `out' member. */ virtual ~outstream_t() {} /* Only present to allow derivation - enables cmm progammes to derive from outstream_t and use multimethods to get different output behaviour from the parser. */ std::ostream& out; bool remove_virtual_from_functionparams; bool remove_static_virtual_prefixes; bool include_declleft; exceptions_translation exceptiontranslation; bool simplenode_t_output_main; // default true. bool simplenode_t_output_space; // default true - output trailing white space. bool simplenode_t_output_extra; // default true - output trailing comments/# lines. }; /* See parser-nodemethods.cpp for the definitions of all virtual functions in the classes defined here. */ struct node_t /* Base for classes that represent logical regions of C++ source. Lowest-level derived classes represent keywords, identifiers etc. Higher-level derived classes represent declarations, functions etc etc. */ { protected: node_t(); // Only allow derived classes. public: /* All non-abstract node_t's have two functions like: static const char* static_description(); virtual const char* description() const; They return identical strings. First is for use in templates, where the node_t type is a template param; second is for use at runtime, where one has an actual instance of a node. Things are clumsy, because each derived class has to have a duplicate of the virtual Description2 function; can't think of a better way... */ virtual const char* description() const = 0; /* Next two members point to start and end of this node in the original source. I.e. creating a node_t requires that the text it is created from outlasts the node_t. */ const char* begin; const char* end; void set_text( const char* text); /* Makes being and end point to start and end of `text', which is assumed to be persistent for the lifetime of the node_t. */ void set_text( const char* begin, const char* end); /* Sets beging and end members directly. */ virtual void output( outstream_t& out) const = 0; /* This outputs whatever this node represents. Including any trailing space, which is useful to make the output identical to input. */ void output_compact( outstream_t& out) const; /* Outputs with all sequences of whitespace replaced by a single space, and no trailing white space. */ std::string output_tostring() const; std::string output_compact_tostring() const; /* Returns (by value) a string containing whatever the Output/output_compact member function outputs. A default -constructed temporary outstream_t is used.*/ virtual void output_tech( outstream_t& out) const; std::string output_tech_tostring() const; /* For debugging only */ /* Next few operators do deep comparisons . if_t dynamic types are different, returns false, else returns a.equal( b). */ friend bool operator == ( const node_t& a, const node_t& b) { if (typeid(a) != typeid(b)) return false; return a.equal( b); } friend bool operator != ( const node_t& a, const node_t& b) { return !(a==b); } // Next few do a default plain string comparison with node_t::begin..node_t::end. friend bool operator == ( const node_t& a, const char* s); friend bool operator != ( const node_t& a, const char* s) { return !(a==s); } friend bool operator == ( const char* s, const node_t& a) { return a==s; } friend bool operator != ( const char* s, const node_t& a) { return a!=s; } virtual ~node_t(); static int number_of_nodes; /* for debugging - keeps track of total nuber of constructed node_t's. */ private: virtual bool equal( const node_t& rhs) const = 0; /* On entry, dynamic type of rhs is assumed to be same as dynamic type of this. Derived classes implement this. This function is called only by the operator = method above.*/ }; #ifdef CMM_MULTIMETHODS void output_node( virtual const parser::node_t& node, virtual parser::outstream_t& out); /* if_t CMM_MULTIMETHODS is defined, Cmm builds slightly differently. Default implementation will call node::output( out), but the user can write their own Output2_() functions to specialise on the node and/or out type. When building the cmm programme itself, CMM_MULTIMETHODS is not defined. It is intended for use by programmes that use some of the Cmm code as a library. This is in top-level namespace 'cos cmm can't cope otherwise. */ #else void output_node( const parser::node_t& node, parser::outstream_t& out); /* Default output fn simply calls node.output( out). */ #endif struct simplenode_t : node_t // A node where contents can be treated as plain text for purposes of comparisons. { virtual void output( outstream_t& out) const; virtual void output_tech( outstream_t& out) const; virtual bool equal( const node_t& rhs0) const; node_t* extra; /* Any trailing #line directives or C/C++ comments are included here so that the parser doesn't seem them. Note that this->begin and this->end /don't/ include the node(s) in 'extra'. */ protected: simplenode_t() : extra( NULL) {} // Only allow derived instances }; struct endoffile_t : simplenode_t { static const char* static_description() { return ""; } virtual const char* description() const { return static_description(); } virtual bool equal( const node_t& rhs); }; struct misc_t : simplenode_t { static const char* static_description() { return ""; } virtual const char* description() const { return static_description(); } }; struct comment_or_hash_t : simplenode_t { static const char* static_description() { return " <#...>"; } virtual const char* description() const { return static_description(); } protected: comment_or_hash_t() {} }; struct hash_t : comment_or_hash_t { static const char* static_description() { return "#"; } virtual const char* description() const { return static_description(); } }; struct hash_line_t : hash_t { hash_line_t() : linenumber( 0), filename() {} static const char* static_description() { return "#line ..."; } virtual const char* description() const { return static_description(); } virtual bool equal( const node_t& rhs0); int linenumber; std::string filename; // could be empty. }; struct comment_t : comment_or_hash_t { protected: comment_t() {} }; struct c_comment_t : comment_t { static const char* static_description() { return "/*...*/"; } virtual const char* description() const { return static_description(); } }; struct cpp_comment_t : comment_t { static const char* static_description() { return "//..."; } virtual const char* description() const { return static_description(); } }; /* Each keyword has it's own type. Keywords are all lexical elements of C++, such as int, double, +, -, *, -> etc etc. We use some nasty temporary macros to make these type definitions managable. */ struct keyword_t : simplenode_t // Base for all keyword types { static const char* static_description() { return ""; } virtual const char* description() const { return static_description(); } protected: keyword_t() {} // Only allow derived types to be created }; struct operator_keyword_t : keyword_t /* a keyword that is also an operator - useful to make this a separate class for checking whether a lexical element is an operator. */ { static const char* static_description() { return ""; } virtual const char* description() const { return static_description(); } }; #define parser_JOIN( a, b) a ## b #define parser_KEYWORD( name, text, base_class)\ struct parser_JOIN( keyword_, name) : base_class\ {\ static const char* static_description() { return text; }\ virtual const char* description() const { return static_description(); }\ static const char* name_t() { return text; } /* Used by lexer to match with text */\ \ /* Remaining lines are constructors: */\ explicit parser_JOIN( keyword_, name)() {}\ explicit parser_JOIN( keyword_, name)( const char* begin0, const char* end0)\ {\ begin=begin0;\ end=end0;\ }\ explicit parser_JOIN( keyword_, name)( const char* begin0)\ {\ begin=begin0;\ end=begin0+strlen( begin0);\ }\ }; /* In the above parser_KEYWORD( name, text) macro, `name' is the name of the struct that will be created to represent the keyword. This will be prefixed by `Keyword_'. `text' is this keyword's text, used by lexer when looking for the keyword in input text. Line-splitting using `\' has not been done because it causes problems when this source code is moved between platforms with different end-of-line conventions. For example, gcc 2.95.2 (surprisingly) doesn't treat `\' followed by CR-LF as a line continuation. */ /* Define types for all non-alphanumeric keywords like '::'. generated types are called keyword_COLON, keyword_OPENCURLY etc. */ /* First, define pairs of types for lexical elements that can be followed immediately by an '='. For example '=', '+'. The names for these are 'Keyword_EQ', 'Keyword_EQEQ', 'Keyword_PLUS', keyword_PLUSEQ' etc.*/ #define parser_KEYWORD_WITH_OPERATOR_EQ( name, chars)\ parser_KEYWORD( parser_JOIN( name, EQ), chars "=", operator_keyword_t)\ parser_KEYWORD( name, chars, operator_keyword_t) parser_KEYWORD_WITH_OPERATOR_EQ( GTGT, ">>") parser_KEYWORD_WITH_OPERATOR_EQ( GT, ">") parser_KEYWORD_WITH_OPERATOR_EQ( LTLT, "<<") parser_KEYWORD_WITH_OPERATOR_EQ( LT, "<") parser_KEYWORD_WITH_OPERATOR_EQ( TILDE, "~") parser_KEYWORD_WITH_OPERATOR_EQ( EQ, "=") parser_KEYWORD_WITH_OPERATOR_EQ( NOT, "!") parser_KEYWORD_WITH_OPERATOR_EQ( AMPAMP, "&&") parser_KEYWORD_WITH_OPERATOR_EQ( AND, "&&") parser_KEYWORD_WITH_OPERATOR_EQ( AMP, "&") parser_KEYWORD_WITH_OPERATOR_EQ( OROR, "||") parser_KEYWORD_WITH_OPERATOR_EQ( OR, "|") parser_KEYWORD_WITH_OPERATOR_EQ( XOR, "^") parser_KEYWORD_WITH_OPERATOR_EQ( DIV, "/") parser_KEYWORD_WITH_OPERATOR_EQ( STAR, "*") parser_KEYWORD_WITH_OPERATOR_EQ( PLUSPLUS, "++"); parser_KEYWORD_WITH_OPERATOR_EQ( MINUSMINUS, "--"); parser_KEYWORD_WITH_OPERATOR_EQ( PLUS, "+") parser_KEYWORD_WITH_OPERATOR_EQ( MINUS, "-") parser_KEYWORD_WITH_OPERATOR_EQ( PERCENT, "%") parser_KEYWORD_WITH_OPERATOR_EQ( sizeof, "sizeof") /* Now for the rest of the non-alphanumeric lexical elements */ parser_KEYWORD( COLONCOLON, "::", keyword_t) parser_KEYWORD( COLON, ":", keyword_t) parser_KEYWORD( OPENROUND, "(", keyword_t) parser_KEYWORD( CLOSEROUND, ")", keyword_t) parser_KEYWORD( OPENSQUARE, "[", keyword_t) parser_KEYWORD( CLOSESQUARE, "]", keyword_t) parser_KEYWORD( OPENCURLY, "{", keyword_t) parser_KEYWORD( CLOSECURLY, "}", keyword_t) parser_KEYWORD( QUESTION, "?", keyword_t) parser_KEYWORD( SEMICOLON, ";", keyword_t) parser_KEYWORD( COMMA, ",", keyword_t) parser_KEYWORD( DOTDOTDOT, "...", keyword_t) parser_KEYWORD( DOT, ".", operator_keyword_t) parser_KEYWORD( ARROW, "->", operator_keyword_t) parser_KEYWORD( AMPERSAND, "@", keyword_t) /* Types for all alphanumeric keywords. The generated types are called (for example) keyword_class, keyword_double etc etc. */ # define parser_KEYWORD_TEXTUAL( name) parser_KEYWORD( name, #name, keyword_t) parser_KEYWORD_TEXTUAL( class) parser_KEYWORD_TEXTUAL( struct) parser_KEYWORD_TEXTUAL( private) parser_KEYWORD_TEXTUAL( protected) parser_KEYWORD_TEXTUAL( public) parser_KEYWORD_TEXTUAL( virtual) parser_KEYWORD_TEXTUAL( enum) parser_KEYWORD_TEXTUAL( for) parser_KEYWORD_TEXTUAL( while) parser_KEYWORD_TEXTUAL( const) parser_KEYWORD_TEXTUAL( volatile) parser_KEYWORD_TEXTUAL( char) parser_KEYWORD_TEXTUAL( int) parser_KEYWORD_TEXTUAL( double) parser_KEYWORD_TEXTUAL( float) parser_KEYWORD_TEXTUAL( long) parser_KEYWORD_TEXTUAL( short) parser_KEYWORD_TEXTUAL( operator) parser_KEYWORD_TEXTUAL( bool) parser_KEYWORD_TEXTUAL( namespace) parser_KEYWORD_TEXTUAL( template) parser_KEYWORD_TEXTUAL( typedef) parser_KEYWORD_TEXTUAL( inline) parser_KEYWORD_TEXTUAL( extern) parser_KEYWORD_TEXTUAL( signed) parser_KEYWORD_TEXTUAL( unsigned) parser_KEYWORD_TEXTUAL( static) parser_KEYWORD_TEXTUAL( typename) parser_KEYWORD_TEXTUAL( using) parser_KEYWORD_TEXTUAL( union) parser_KEYWORD_TEXTUAL( new) parser_KEYWORD_TEXTUAL( throw) parser_KEYWORD_TEXTUAL( delete) parser_KEYWORD_TEXTUAL( return) parser_KEYWORD_TEXTUAL( friend) parser_KEYWORD_TEXTUAL( if) parser_KEYWORD_TEXTUAL( else) parser_KEYWORD_TEXTUAL( explicit) parser_KEYWORD_TEXTUAL( catch) parser_KEYWORD_TEXTUAL( try) parser_KEYWORD_TEXTUAL( switch) parser_KEYWORD_TEXTUAL( case) parser_KEYWORD_TEXTUAL( default) parser_KEYWORD_TEXTUAL( do) parser_KEYWORD_TEXTUAL( mutable) parser_KEYWORD_TEXTUAL( register) parser_KEYWORD_TEXTUAL( void) parser_KEYWORD_TEXTUAL( asm) #undef parser_JOIN #undef parser_KEYWORD_TEXTUAL #undef parser_KEYWORD_WITH_OPERATOR_EQ #undef parser_KEYWORD struct identifier_t : simplenode_t // string of alnum_ characters, starting with alpha character { static const char* static_description() { return "identifier"; } virtual const char* description() const { return static_description(); } }; struct number_t : simplenode_t { static const char* static_description() { return "number"; } virtual const char* description() const { return static_description(); } }; struct string_t : simplenode_t // Things in single/double quotes { static const char* static_description() { return "string"; } virtual const char* description() const { return static_description(); } void OutputContents( outstream_t& out) const; /* Outputs contents with escape characters expanded and no enclosing quotes. doesn't handle octal stuff yet. */ std::string GetContents() const; }; struct logical_namespace_t // Base-class for namespace and class/struct. { logical_namespace_t() : parent( NULL), leafname( NULL), items() {} virtual ~logical_namespace_t() {} virtual void append_item( node_t* item); // should prob be pure - this impl throws. node_t* GetParentElement( int i) const; void output_complete( outstream_t& out) const; typedef std::vector< node_t*> items_t; logical_namespace_t* parent; node_t* leafname; // can be NULL, or name_element_t or identifier_t. items_t items; }; struct declarator_t; struct name_t; struct namespace_t : node_t, logical_namespace_t { namespace_t() : namespac( NULL), opencurly( NULL), closecurly( NULL) {} static const char* static_description() { return "namespace name {...}"; } virtual const char* description() const { return static_description(); } virtual void append_item( node_t* item); virtual void output( outstream_t& out) const; virtual bool equal( const node_t& rhs0) const; keyword_namespace* namespac; keyword_OPENCURLY* opencurly; keyword_CLOSECURLY* closecurly; }; struct linkage_t : simplenode_t, logical_namespace_t // don't think linkage should be a namespac...? { linkage_t() : exter( NULL), linkagename( NULL), opencurly( NULL), closecurly( NULL) {} static const char* static_description() { return "extern \"...\" {...}"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; keyword_extern* exter; const string_t* linkagename; keyword_OPENCURLY* opencurly; // can be NULL, in which case there should be 1 item in nodes. keyword_CLOSECURLY* closecurly; // can be NULL. }; struct template_specialisation_itembase_t : simplenode_t // either a compile-time expression or a declarator { static const char* static_description() { return "TemplateBracketsItem_Base"; } virtual const char* description() const { return static_description(); } keyword_COMMA* terminating_comma; // `,' or NULL if terminator is `>'. protected: template_specialisation_itembase_t() : terminating_comma( NULL) {} }; struct declarator_names_t; struct template_specialisation_item_type_t : template_specialisation_itembase_t { template_specialisation_item_type_t() : declnames() {} static const char* static_description() { return "class|typename "; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; declarator_names_t* declnames; // e.g. `foo* const', i.e. anonymous. }; struct expression_t; struct template_specialisation_item_expression_t : template_specialisation_itembase_t // should be called `compile-time expression' or something. { template_specialisation_item_expression_t() : expression( NULL) {} static const char* static_description() { return "template-specifier"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; expression_t* expression; // e.g. `4*5' in mytype< 4*5> }; struct template_specialisation_t : simplenode_t /* represents <...> that follows a name, i.e. the <...> part of a specialisation. Does not represent the <...> that can follow the `template' keyword. */ { template_specialisation_t() : lt(), items(), gt() {} static const char* static_description() { return "<...> not following template"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; virtual void output_tech( outstream_t& out) const; typedef std::vector< template_specialisation_itembase_t*> items_t; keyword_LT* lt; items_t items; keyword_GT* gt; }; struct templatesingle_itembase_t : simplenode_t { static const char* static_description() { return "item inside <...> following `template'"; } virtual const char* description() const { return static_description(); } }; struct templatesingle_itemclasstypename_t : templatesingle_itembase_t { templatesingle_itemclasstypename_t() : class_or_typename(), identifier(), comma() {} static const char* static_description() { return "`class ...' inside <...> following `template'"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; keyword_t* class_or_typename; identifier_t* identifier; keyword_COMMA* comma; // can be null if this last item, terminated by `>'. }; struct templatesingle_itemother_t : templatesingle_itembase_t { templatesingle_itemother_t() : class_or_typename(), declnames() {} static const char* static_description() { return "non-`class ...' <...> following `template'"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; keyword_t* class_or_typename; declarator_names_t* declnames; }; struct template_single_t : simplenode_t { template_single_t() : templat( NULL), lt( NULL), items(), gt( NULL) {} static const char* static_description() { return "template<...>"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; typedef std::vector< templatesingle_itembase_t*> items_t; keyword_template* templat; keyword_LT* lt; items_t items; keyword_GT* gt; }; struct template_t : simplenode_t /* represents 'template<...> [template<...>]. didn't realise that one could have more than one template<...>, but gcc's STL library does - for template members I think */ { template_t() : singles() {} static const char* static_description() { return "template<...>*"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; std::vector< template_single_t*> singles; }; struct multiple_nodes_t : node_t /* Used in the many cases when the parser doesn't fully analyse the source. */ { multiple_nodes_t() : items() {} static const char* static_description() { return ""; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; virtual bool equal( const node_t& rhs0) const; typedef std::vector< node_t*> items_t; items_t items; }; struct square_brackets_t : simplenode_t { square_brackets_t() : open( NULL), close( NULL) {} static const char* static_description() { return "[]"; } virtual const char* description() const { return static_description(); } keyword_OPENSQUARE* open; keyword_CLOSESQUARE* close; }; struct block_t : node_t { static const char* static_description() { return "{...}/[...]/<...>/(...)"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; virtual bool equal( const node_t& rhs0) const; block_t() : open( NULL), items(), close( NULL) {} node_t* open; multiple_nodes_t items; node_t* close; }; struct assembler_block_t : node_t { assembler_block_t() : as( NULL), items( NULL), semicolon( NULL) {} static const char* static_description() { return "asm(...)"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; virtual bool equal( const node_t& rhs0) const; keyword_asm* as; block_t* items; keyword_SEMICOLON* semicolon; }; struct name_element_t : node_t /* Abstract class; represents element of a fully-qualified name, eg foo::bar would be represented by two NameElements `foo' and `::bar'. */ { static const char* static_description() { return "[::]"; } virtual const char* description() const { return static_description(); } virtual void output_tech( outstream_t& out) const; virtual bool equal( const node_t& rhs0) const; keyword_COLONCOLON* coloncolon; // can be NULL template_specialisation_t* templatespec; // can be NULL. protected: name_element_t() : coloncolon( NULL), templatespec( NULL) {} }; struct name_element_member_ptr_t : name_element_t { name_element_member_ptr_t() : star( NULL) {} virtual void output( outstream_t& out) const; keyword_STAR* star; }; struct name_element_destructor_t : name_element_t { name_element_destructor_t() : tilde( NULL), name( NULL) {} virtual void output( outstream_t& out) const; keyword_TILDE* tilde; name_t* name; }; struct name_element_operator_t : name_element_t // for things like `std::operator ==' { name_element_operator_t() : operatio( NULL), operation( NULL) {} static const char* static_description() { return "[::]operator"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; virtual bool equal( const node_t& rhs0) const; keyword_operator* operatio; node_t* operation; /* would be keyword_t*, except that we have to be able to represent `()' and `[]', which aren't a single keyword_t node. Also, has to represent *, e.g. operator void* (). */ }; struct name_element_normal_t : name_element_t // A name element that is a simple name optionally preceded by `::'. { name_element_normal_t() : identifier( NULL) {} static const char* static_description() { return "[::][template<...>]"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; virtual bool equal( const node_t& rhs0) const; identifier_t* identifier; }; struct nameelement_template_t : name_element_t // A name element that is `template'. next name element will not have preceding `::'. { nameelement_template_t() : templat( NULL) {} static const char* static_description() { return "[::][template<...>]"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; const keyword_template* templat; }; struct context_t; struct name_t : node_t // A compund name, eg `std::runtime_error'. { name_t() : namespac( NULL), elements() {} static name_t* MakeName( const char* text, context_t& context); static name_t* MakeName( identifier_t& identifier, context_t& context); /* could make these into constructors, but it's easier to create new name on the heap - see the implementation. A copy is made of `text'. */ static const char* static_description() { return "{[::]}*"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; virtual bool equal( const node_t& rhs0) const; void output_complete( outstream_t& out) const; // Outputs fully qualified name, including any namespace elements implied by this->namespac. virtual void output_tech( outstream_t& out) const; node_t* GetElement( unsigned int i) const; /* Takes the complete qualified name, and returns the i-th element, with i=1 being the namespace containing the leaf element, i=1,2... being progressively less nested namespace names. Returns NULL if i is >= than the number of elements in the completely qualified name. Note that i=0 is not allowed - the leaf element doesn't have to be an identifier_t.*/ friend bool NamespacesEq( const name_t& lhs, const name_t& rhs); // Ignores leaf element. typedef std::vector< name_element_t*> elements_t; logical_namespace_t* namespac; elements_t elements; }; struct namespace_eq_t : simplenode_t { namespace_eq_t() : namespac( NULL), name( NULL), eq( NULL), namespacerhs( NULL), semicolon( NULL) {} static const char* static_description() { return "namespace =;"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; keyword_namespace* namespac; identifier_t* name; keyword_EQ* eq; name_t* namespacerhs; keyword_SEMICOLON* semicolon; }; struct enum_t : simplenode_t { enum_t() : enu( NULL), identifier( NULL), block( NULL), semicolon( NULL) {} static const char* static_description() { return "enum {...};"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; keyword_enum* enu; identifier_t* identifier; // can be NULL block_t* block; keyword_SEMICOLON* semicolon; }; struct union_t : node_t { union_t() : unio( NULL), identifier( NULL), block( NULL), semicolon( NULL) {} static const char* static_description() { return "union {...};"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; keyword_union* unio; identifier_t* identifier; // can be NULL block_t* block; keyword_SEMICOLON* semicolon; }; struct using_t : simplenode_t { using_t() : usin( NULL), namespac( NULL), name( NULL), semicolon( NULL) {} static const char* static_description() { return "using [namespace] "; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; keyword_using* usin; keyword_namespace* namespac; // can be NULL name_t* name; keyword_SEMICOLON* semicolon; }; struct modifiers_t : node_t /* Not a node, because modifiers don't necessarily represent a contiguou region of source. Eg `const int volatile'. */ { modifiers_t() : items() {} virtual ~modifiers_t() {} static const char* static_description() { return "{const|volatile|virtual|...}"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; virtual void output_tech( outstream_t& out) const; virtual bool equal( const node_t& rhs0) const; void OutputLeftSide( outstream_t& out, const char* pos) const; void OutputRightSide( outstream_t& out, const char* pos) const; /* prev two fns are to allow output that preserves the ordering of modifiers - eg so that 'const int' is not output as 'int const'. Allows the parser to be tested by simply doing a diff between it's input and output. See declarator_left_t's Output methods. */ typedef std::vector< node_t*> items_t; items_t items; }; struct internal_t : simplenode_t /* Represents special things that are not standard C++. e.g gcc's __attribute__(...). */ { internal_t() : identifier( NULL), extra0(), extra( NULL) {} // Would be better to just have a multiple_nodes_t member, and let the parsing code fill it in. static const char* static_description() { return ""; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; const identifier_t* identifier; multiple_nodes_t extra0; node_t* extra; }; struct declarator_t; struct declarator_left_t; struct function_t; struct declarator_name_t; struct declarator_t : node_t /* base type for rhs of all declarations - things like: (*foo)(int), x[], *y A declaration is represented by a singly-linked list of declarator_t structs (linked together by declarator_t::subtype), that is terminated by a declarator_left_t - the plain type that is always the left-most part of a declaration in source code. For example, `int (*foo)(double)' would be represented as the following single-linked list of declarator_t structs: Type Source code ---------------------------------- declarator_name_t foo pointer_t * bracket_declarator_t () Function (double) declarator_left_t int The top-level declaration is the declarator_name_t that represents 'foo'. The `subtype' member of this points to a pointer_t, whose subtype member will point to a bracket_declarator_t etc etc, eventually ending up with a subtype member that points to the declarator_left_t. This will have a NULL subtype member. Note that we can represent nameless types. `int (*)(double)' would be represented by the pointer_t element in the above list. Thus, given a named type, the nameless type is the named type's subtype member. Sometimes a declarator_t's text is in two pieces in the original text, separated by the higher-up declarator_t. In the above example, bracket_declarator_t consists of `(' and `)' separated by the `*foo'. */ { static const char* static_description() { return ""; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; virtual void output_left( outstream_t& out) const; virtual void output_right( outstream_t& out) const; void output_complete( outstream_t& out) const; std::string output_complete_tostring() const; virtual bool equal( const node_t& rhs0) const; void output_anonymous( outstream_t& out); declarator_left_t* is_simple_reference(); // Returns NULL if not a simple reference, else returns what it is a simple reference for. declarator_left_t* is_simple_type(); // Returns NULL if not a simple reference, else returns what it is a simple reference for. function_t* is_simple_function(); // Returns NULL if not a function. declarator_t* logical_subtype(); // Skips bracket_declarator_t-s. declarator_name_t* is_name(); // Returns NULL if not a declarator_name_t. virtual declarator_left_t* get_declarator_left(); // Returns NULL if there isn't a declarator_left_t at the end of the chain of subtypes. internal_t* leading_internal; declarator_t* subtype; internal_t* trailing_internal; // eg '__attribute__(...)' protected: declarator_t() : leading_internal( NULL), subtype( NULL), trailing_internal( NULL) {} // only allow derived types. }; struct struct_name_t : node_t { struct_name_t() : struc( NULL), name( NULL), block( NULL) {} static const char* static_description() { return "struct [{...}]"; } virtual const char* description() const { return static_description(); } virtual void output( outstream_t& out) const; virtual bool equal( const node_t& rhs) const; keyword_struct* struc; identifier_t* name; // can be null block_t* block; // can be null }; struct label_t : simplenode_t { label_t() : identifier( NULL), colon( NULL) {} static const char* static_description() { return "