1 /*===========================================================================
2  *
3  *                            PUBLIC DOMAIN NOTICE
4  *               National Center for Biotechnology Information
5  *
6  *  This software/database is a "United States Government Work" under the
7  *  terms of the United States Copyright Act.  It was written as part of
8  *  the author's official duties as a United States Government employee and
9  *  thus cannot be copyrighted.  This software/database is freely available
10  *  to the public for use. The National Library of Medicine and the U.S.
11  *  Government have not placed any restriction on its use or reproduction.
12  *
13  *  Although all reasonable efforts have been taken to ensure the accuracy
14  *  and reliability of the software and data, the NLM and the U.S.
15  *  Government do not and cannot warrant the performance or results that
16  *  may be obtained by using this software or data. The NLM and the U.S.
17  *  Government disclaim all warranties, express or implied, including
18  *  warranties of performance, merchantability or fitness for any particular
19  *  purpose.
20  *
21  *  Please cite the author in any work or product based on this material.
22  *
23  * ===========================================================================
24  *
25  */
26 
27 #include "ParseTree.hpp"
28 
29 #include <stdexcept>
30 
31 #include <klib/text.h>
32 #include <klib/printf.h>
33 
34 using namespace std;
35 using namespace ncbi::SchemaParser;
36 
37 static const uint32_t ChildrenBlockSize = 1024; //TODO: pick a good initial size
38 
39 static
40 void
ThrowRc(const char * p_msg,rc_t p_rc)41 ThrowRc ( const char* p_msg, rc_t p_rc )
42 {
43     char msg[1024];
44     string_printf ( msg, sizeof msg, NULL, "%s, rc = %R", p_msg, p_rc );
45     //INTERNAL_ERROR ( xcUnexpected, "VectorRemove: rc = %R", rc );
46     throw logic_error ( msg );
47 }
48 
49 // ParseTree
50 
ParseTree(const Token & p_token)51 ParseTree :: ParseTree ( const Token& p_token )
52 :   m_token ( p_token ),
53     m_location ( & m_token . GetLocation () )
54 {
55     VectorInit ( & m_children, 0, ChildrenBlockSize );
56 }
57 
DestroyChild(void * item,void *)58 void DestroyChild ( void * item, void * )
59 {
60     delete ( ParseTree * ) item;
61 }
62 
~ParseTree()63 ParseTree :: ~ParseTree ()
64 {
65     VectorWhack ( & m_children, DestroyChild, NULL );
66 }
67 
68 void
AddChild(ParseTree * p_node)69 ParseTree :: AddChild ( ParseTree * p_node )
70 {
71     assert ( m_location != 0 );
72     assert ( p_node != 0 );
73     if ( m_location -> m_line == 0 )
74     {   // assume p_node's location will not change in the future
75         m_location = & p_node -> GetLocation ();
76     }
77     VectorSet ( & m_children, VectorLength ( & m_children ), p_node );
78 }
79 
80 uint32_t
ChildrenCount() const81 ParseTree :: ChildrenCount () const
82 {
83     return VectorLength ( & m_children );
84 }
85 
86 const ParseTree*
GetChild(uint32_t p_idx) const87 ParseTree :: GetChild ( uint32_t p_idx ) const
88 {
89     return ( const ParseTree * ) VectorGet ( & m_children, p_idx );
90 }
91 
92 ParseTree*
GetChild(uint32_t p_idx)93 ParseTree :: GetChild ( uint32_t p_idx )
94 {
95     return ( ParseTree * ) VectorGet ( & m_children, p_idx );
96 }
97 
98 void
MoveChildren(ParseTree & p_source)99 ParseTree :: MoveChildren ( ParseTree& p_source )
100 {
101     VectorWhack ( & m_children, DestroyChild, NULL );
102     VectorCopy ( & p_source . m_children, & m_children );
103     VectorWhack ( & p_source . m_children, NULL, NULL );
104 }
105 
106 // ParseTreeScanner
107 
108 static const uint32_t StackBlockSize    = 1024; //TODO: pick a good initial size
109 
ParseTreeScanner(const ParseTree & p_root,const char * p_source)110 ParseTreeScanner :: ParseTreeScanner ( const ParseTree& p_root, const char * p_source )
111 : m_source ( string_dup ( p_source, string_size (p_source ) ) )
112 {
113     VectorInit ( & m_stack, 0, StackBlockSize );
114     PushNode ( & p_root );
115 }
116 
~ParseTreeScanner()117 ParseTreeScanner :: ~ParseTreeScanner ()
118 {
119     free ( m_source );
120     VectorWhack ( & m_stack, NULL, NULL );
121 }
122 
123 static const ParseTree ChildrenOpen  ( Token ( '(' ) );
124 static const ParseTree ChildrenClose ( Token ( ')' ) );
125 
126 void
PushNode(const ParseTree * p_node)127 ParseTreeScanner :: PushNode ( const ParseTree* p_node )
128 {
129 //cout << "pushing " << p_node -> GetToken () . GetType () << endl;
130     VectorAppend ( & m_stack, NULL, p_node );
131 }
132 
133 Token :: TokenType
NextToken(const Token * & p_token)134 ParseTreeScanner :: NextToken ( const Token*& p_token )
135 {
136     while ( VectorLength ( & m_stack ) != 0 )
137     {
138         const ParseTree* node;
139         rc_t rc = VectorRemove ( & m_stack, VectorLength ( & m_stack ) - 1, ( void ** ) & node );
140         if ( rc != 0 )
141         {
142             ThrowRc ( "VectorRemove", rc );
143         }
144 
145         assert ( node != 0 );
146 //cout << "popped " << node -> GetToken () . GetType () << endl;
147 
148         uint32_t count = node -> ChildrenCount ();
149         if ( count > 0 )
150         {   // push '(' children ')' in reverse order
151             PushNode ( & ChildrenClose );
152 
153             for ( uint32_t i = count; i > 0; --i )
154             {
155                 PushNode ( node -> GetChild ( i - 1 ) );
156             }
157 
158             PushNode ( & ChildrenOpen );
159         }
160 
161         p_token = & node -> GetToken ();
162         return p_token -> GetType ();
163     }
164     return Token :: EndSource;
165 }
166