1
// This file is part of PUMA.
2
// Copyright (C) 1999-2003 The PUMA developer team.
4
// This program is free software; you can redistribute it and/or
5
// modify it under the terms of the GNU General Public License as
6
// published by the Free Software Foundation; either version 2 of
7
// the License, or (at your option) any later version.
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
14
// You should have received a copy of the GNU General Public
15
// License along with this program; if not, write to the Free
16
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19
#include "Puma/CTranslationUnit.h"
20
#include "Puma/CTreeMatcher.h"
21
#include "Puma/CMatchChecker.h"
22
//#include "Puma/CRankTable.h"
23
#include "Puma/RegComp.h"
24
#include "Puma/CTree.h"
25
#include "Puma/StrCol.h"
32
void CTreeMatcher::init (CTree *matchTree, unsigned int max) {
36
// Set the current match tree.
37
_matchTree = matchTree;
40
void CTreeMatcher::pre_visit (CTree *node) {
41
// Do nothing on visit if no match tree is given.
42
if (! _matchTree || ! node)
45
// Check whether this node is really the expected node and not
46
// maybe someone that only looks like it.
50
// If the match tree can't be a sub tree of the current C++ syntax
51
// tree node, trying to match this node and its sons is skipped.
52
// if (CRankTable::Rank (node->astName ()) <
53
// CRankTable::Rank (_matchTree->astName ()))
56
// Create CMatch object and add the current node to it.
57
CMatch *matchObj = new CMatch;
58
matchObj->add (node, "root");
60
// If the current sub-tree is matching the match tree, call
61
// action() with the current node and the nodes that correspond
62
// with the any-nodes of the match tree as arguments.
63
if (match (node, _matchTree, matchObj)) {
66
if (_max_mobjs <= _num_mobjs && _max_mobjs != 0)
67
abort (); // Abort traversing the syntax tree!
69
// Not matching. Delete the match object.
74
// Return true if the current sub-tree is matching the match tree.
75
bool CTreeMatcher::match (CTree *currTree, CTree *matchTree,
76
CMatch* matchObj) const {
77
if (! currTree || ! matchTree || ! matchObj)
80
// Don't compare against CT_ImplicitCast nodes.
81
while (currTree->NodeName () == CT_ImplicitCast::NodeId ())
82
currTree = currTree->Son (0);
84
// The current node of the match tree is an Any node.
85
if (matchTree->NodeName () == CT_Any::NodeId () ||
86
matchTree->NodeName () == CT_AnyList::NodeId ()) {
87
CT_AnyExtension *ext = ((CT_Any*)matchTree)->Extension ();
88
CTree *condition = ext ? ext->Condition () : (CTree*)0;
89
const char *name = ext ? ext->Name () : (const char*)0;
90
Array<CTree *> *old = &matchObj->get (name);
92
// If there already is an Any node with that name, it has
93
// to be checked whether the two trees are the same.
95
if (! match (old->get (0), currTree, matchObj))
98
// If there is no extra condition for matching with this
99
// any-node, the current tree node always is matching.
103
// Tell the match-parser which condition keywords are allowed.
104
if (matchTree->NodeName () == CT_Any::NodeId ())
106
else if (matchTree->NodeName () == CT_AnyList::NodeId ())
109
if (! evalMatchCondition (currTree, condition, matchObj, mode))
113
// Remember anys with a name only.
115
matchObj->add (currTree, name);
120
// If the current node of the match tree isn't an any-node
121
// the two current nodes must be of the same type and must
122
// have the same number of sons.
123
if (currTree->NodeName () != matchTree->NodeName () ||
124
currTree->Sons () != matchTree->Sons ())
127
// The current nodes are tokens. The text of the tokens
129
if (currTree->NodeName () == CT_Token::NodeId ()) {
130
if (! currTree->token () || ! matchTree->token ())
132
if (! currTree->token ()->text () || ! matchTree->token ()->text ())
134
if (strcmp (currTree->token ()->text (),
135
matchTree->token ()->text ()) != 0)
139
// Now call match() for every son of the current node.
140
for (int i = 0; i < currTree->Sons (); i++)
141
if (! match (currTree->Son (i), matchTree->Son (i), matchObj))
144
// The current C++ sub-tree is matching the current sub-tree
145
// of the match tree.
149
// Match any node-list.
150
int CTreeMatcher::matchList (int mode, match_state &mstate,
151
CTree *mt, CTree *f, CTree *l) const {
152
bool matched = false;
153
CT_List *list = (CT_List*)mstate.tree;
154
int elements = list->Entries ();
155
int sign_f = 0, sign_l = 0;
158
sign_f = (f->token ()->text ().c_str ()[0] == '-') ? -1 : 1;
159
f = f->Son (f->Sons () - 1);
162
sign_l = (l->token ()->text ().c_str ()[0] == '-') ? -1 : 1;
163
l = l->Son (l->Sons () - 1);
166
// Get the arguments.
167
int first = (f) ? (sign_f * (int) strtol (f->token ()->text (), NULL, 10)) : 1;
168
int last = (l) ? (sign_l * (int) strtol (l->token ()->text (), NULL, 10)) : elements;
170
// Compute the real element number.
171
if (first < 0) first = elements + first + 1;
172
if (last < 0) last = elements + last + 1;
175
if (first <= 0 || last <= 0)
178
// The current list has too few elements.
179
if (first > elements || last > elements)
182
// If the two arguments have the same value, the user wanted
183
// to match lists that have exact the given number of elements.
184
if (first == last && f && l) {
185
if (first != elements)
192
// Match a single element.
196
// Match the list elements.
197
for (int i = first; i <= last; i++)
198
if (matchTree (mode, mstate, list->Entry (i - 1), mt))
201
// Return the success value.
202
return matched ? 1 : 0;
206
int CTreeMatcher::matchTree (int mode, match_state &mstate, CTree *tree,
211
if (mode == MATCH_ALL ||
212
mode == MATCH_FIRST ||
213
mode == MATCH_LAST ||
214
mode == MATCH_PRUNE ||
215
mode == MATCH_LEAF) {
216
CMatchChecker check (mode, mt, &tmp);
218
matched = (check.matchFound ()) ? 1 : 0;
220
else if (mode == MATCH_EXACT)
221
matched = (match (tree, mt, &tmp)) ? 1 : 0;
223
// Remember all the matches.
225
mstate.matchObj->combine (&tmp);
230
// Match a node by its name. Regular expressions are allowed.
231
int CTreeMatcher::matchNodeName (CTree *tree, CTree *mt) const {
234
if (mt->NodeName () != CT_String::NodeId ())
237
char *string = StrCol::dup (mt->token ()->text ().c_str () + 1);
238
string[strlen (string) - 1] = '\0';
240
RegComp compare (string);
241
bool matching = compare.match ((const char*)tree->NodeName ());
243
return matching ? 1 : 0;
246
// Start the match process.
247
void CTreeMatcher::match (CTranslationUnit &tUnit,
248
CTranslationUnit &matchUnit, CTree *syntaxtree) {
249
// Do the manipulations only if there really is a syntax tree.
250
CTree *matchtree = matchUnit.tree ();
252
syntaxtree = tUnit.tree ();
255
// tUnit.cppTree ()->context ().push ();
257
// tUnit.cppTree ()->context ().pop ();