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