//@copyright_begin // ================================================================ // Copyright Notice // Copyright (C) 1998-2004 by Joe Linoff // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL JOE LINOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Comments and suggestions are always welcome. // Please report bugs to http://ccdoc.sourceforge.net/ccdoc // ================================================================ //@copyright_end // MULTIPLE INCLUSION GUARD #ifndef ccdoc_phase1_parser_h #define ccdoc_phase1_parser_h /** * This variable allows the header version * to be queried at runtime. */ namespace { char ccdoc_phase1_parser_h_rcsid[] = "$Id: phase1_parser.h,v 1.6 2004/09/30 04:16:07 jlinoff Exp $"; } #include "switches.h" #include "database.h" #include "statement.h" #include "phase1_scanner.h" namespace ccdoc { namespace phase1 { // ================================================================ //@{ // Parser object. // @author Joe Linoff // @version $Id: phase1_parser.h,v 1.6 2004/09/30 04:16:07 jlinoff Exp $ //@} // ================================================================ class parser { public: // ================================================================ //@{ // Expression tree for #if and #elif expression processing. //@} // ================================================================ class cpp_expr { public: // ================================================================ //@{ // Expression tree node for #if and #elif expression processing. // @author Joe Linoff // @version $Id: phase1_parser.h,v 1.6 2004/09/30 04:16:07 jlinoff Exp $ //@} // ================================================================ class node { public: //@{ // The node types. Not all types are covered, only those // that are most likely to simplify the implementation. //@} enum nd_type { nd_type_id, // MACRO id nd_type_num, // number nd_type_def, // defined nd_type_lp, // ( nd_type_rp, // ) nd_type_not, // ! nd_type_and, // && nd_type_or, // || nd_type_eq, // == nd_type_ne, // != nd_type_lt, // < nd_type_le, // <= nd_type_gt, // > nd_type_ge, // >= nd_type_root, nd_type_unknown }; public: //@{ // Get the node type. // @param id The id. // @returns The node type. //@} static nd_type get_type(const string& id); public: //@{ // Constructor. // @param x The expression. // @param t The type. // @param name The node name. The type is figured out from the name. //@} node(cpp_expr& x,nd_type t,const string& name); //@{ // Destructor. //@} ~node(); public: //@{ // Insert the node into the tree near the proposed // parent. // @param parent The proposed parent. // @returns The node that s/b used as the parent for // the next operation. //@} node* insert( node* parent ); public: //@{ @returns The parent. //@} node* get_parent() const {return m_parent;} //@{ @returns The left child. //@} node* get_left() const {return m_left;} //@{ @returns The right child. //@} node* get_right() const {return m_right;} //@{ @returns The node name. //@} const string& get_name() const {return m_name;} //@{ @returns The node type. //@} nd_type get_type() const {return m_type;} //@{ // Get the node type name. // @param t The node type. // @returns The node type name. //@} static const char* get_node_type_name(nd_type t); public: //@{ // Get the hierarchical name. // @returns The hierarchical name. //@} string get_hier_name() const; public: //@{ // Get the hierarchical id path. // @returns The hierarchical id path. //@} string get_hier_id_path() const; public: //@{ // Get the root node. // @returns The root node. //@} node* get_root() const; public: //@{ // Get the node id. // @returns The node id. //@} int get_node_id() const {return m_id;} public: //@{ // Evaluate from the current node downwards. //@} int eval(); public: //@{ //@returns The hierarchical depth. //@} unsigned depth() const; public: //@{ // Debug dump. // @param prefix The debug prefix. //@} void debug_dump(const char* prefix) const; private: void error(const char* x, const char* file, int line); private: node* insert_and(node* parent); node* insert_cmp(node* parent); node* insert_lor(node* parent); node* insert_or(node* parent); node* insert_rp(node* parent); private: int eval_and(); int eval_def(); int eval_eq(); int eval_id(); int eval_ge(); int eval_gt(); int eval_le(); int eval_lp(); int eval_lt(); int eval_ne(); int eval_not(); int eval_num(); int eval_or(); int eval_root(); int eval_rp(); private: node* m_parent; node* m_left; node* m_right; nd_type m_type; const string& m_name; cpp_expr& m_expr; int m_id; }; // ================================================================ // // End of cpp_expr::node. // // ================================================================ public: //@{ // Tree constructor. // @param phase1 The phase1 object with the defines map. //@} cpp_expr(parser& in_parser); //@{ // Destructor. //@} ~cpp_expr(); public: //@{ // Evaluate a statement. // @param stmt The statement. // @param start The starting token index. // @returns True if the statement evaluated to true or // false otherwise. //@} bool eval( vector& stmt, int start); public: //@{ // Is this expression ok? // @returns True if the expression is ok or false otherwise. //@} bool ok() const {return m_errors ? false : true; } public: //@{ // Debug dump. // @param prefix The debug prefix. //@} void debug_dump(const char* prefix) const; public: //@{ // Increment the error count. //@} void inc_errors() {m_errors++;} public: //@{ // Get the next id. // @returns The next node id. //@} int get_next_node_id() {return m_node_id++;} public: //@{ // Get the parser object. // @returns The parser object. //@} parser& get_parser() {return m_parser;} private: parser& m_parser; unsigned m_errors; node* m_root; string m_root_name; int m_node_id; }; // ================================================================ // // End of expr. // // ================================================================ private: //@{ // Manage the action taken for each statement. //
      //   ACCEPT      Accept this statement (store it in the db).
      //   REJECT      Reject this statement.
      //   REJECT_ALL  Reject this statement. It is set after
      //               a valid accept.
      //
// Here is how it works. //
      //   #if exp1         | exp1 == false
      //                    | REJECT
      //   #elif exp2       | exp2 == true
      //                    | ACCEPT
      //   #elif exp3       | exp3 == true
      //                    | REJECT_ALL
      //   #elif exp4       | exp4 == false
      //                    | REJECT_ALL
      //   #else            |
      //                    | REJECT_ALL
      //   #endif
      //
enum ACTION { ACCEPT, REJECT, REJECT_ALL }; public: parser(switches& sw,database& db,const string& name); ~parser(); bool parse(); statement::base::stmts_t& get_stmts() {return m_statements;} private: void add_statement(statement::base*); bool get_next_statement(); bool get_next_token(string& token); statement::base* make_statement( const string& id, statement::base::TYPE ); statement::base* make_statement( const string& id, statement::base::TYPE, vector& tokens ); public: switches& get_sw() const {return m_sw;} public: bool get_debug() const {return m_debug;} void set_debug(bool f) {m_debug=f;m_scanner.set_debug(f);} public: //@{ // Is this macro defined? // @param name The macro name. // @returns True if it is defined or false otherwise. //@} bool defined( const string& name ) const; public: //@{ // Get the macro value. //@param key The macro name. //@param value The macro value. //@} void get_macro_value(const string& key,string& value); public: //@{ // Get the macro int value. //@param key The macro name. //@returns The int value or zero if it was not an int value. //@} int get_macro_value(const string& key); public: //@{ // Get the int value. // @param num The number. // @returns The numeric value. //@} int get_int_value( const string& name ); private: bool parse_scoping_stmt_beg(vector& tokens, statement::base::TYPE t); bool parse_scoping_stmt_end(); bool parse_enum(vector& tokens); bool parse_fct_or_var(vector&); bool parse_operator(vector&); bool parse_var_or_fct(vector&); bool parse_typedef(vector&); bool parse_friend(vector&); bool parse_extern(vector&); void parse_access_specifier(vector&, string&, statement::base::ACCESS); private: void parse_special_members(statement::base*); void parse_special_members(statement::base* stmt, const char* arg_id, bool& default_constructor, bool& copy_constructor); private: void get_fct_id(string& id,statement::base* stmt) const; bool is_id(const string&) const; private: void parse_cpp(); void parse_cpp_define(vector&); void parse_cpp_elif(vector&); void parse_cpp_else(vector&); void parse_cpp_endif(vector&); void parse_cpp_if(vector&); void parse_cpp_ifdef(vector&); void parse_cpp_ifndef(vector&); void parse_cpp_undef(vector&); void parse_cpp_warn(vector&,const char* msg); bool parse_cpp_if_expr(vector&); private: void parse_comment(); statement::base* parse_comment_pkg_info(vector&,string&); private: switches& m_sw; database& m_db; scanner m_scanner; bool m_debug; bool m_parsed; statement::base::stmts_t m_parents; statement::base::stmts_t m_statements; // Issue 0136 // Create a stack for managing special members // so that nested structures are handled correctly. vector m_special_members; switches::defines_type m_defines; vector m_access_specifier; vector m_action; }; } } #endif