farsamiscutilities.cpp
1 /********************************************************************************
2  * FARSA Utilities Library *
3  * Copyright (C) 2007-2012 *
4  * Gianluca Massera <emmegian@yahoo.it> *
5  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
6  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
21  ********************************************************************************/
22 
23 #include "farsamiscutilities.h"
24 
25 namespace farsa {
26 
27 QString removeComments(const QString& program, CommentsPositions* commentsPos, StringsPositions* stringsPos)
28 {
29  // We create the list of comments and strings in any case, even if we don't have to return them
30  CommentsPositions cpos;
31  StringsPositions spos;
32 
33  // To remove comments we read one character at a time and check if it is a comment or not
34  QString cleaned;
35  // The possible states
36  enum RemoveCommentsState {
37  FirstSlash,
38  StartEndCComment,
39  InCComment,
40  InCppComment,
41  InString,
42  InCharacter,
43  NormalCode
44  } state = NormalCode;
45  CommentPosition curComment;
46  StringPosition curString;
47  for (int i = 0; i < program.size(); i++) {
48  switch (state) {
49  case FirstSlash:
50  if (program[i] == '/') {
51  state = InCppComment;
52  curComment.type = CommentPosition::CppComment;
53  } else if (program[i] == '*') {
54  state = InCComment;
55  curComment.type = CommentPosition::CComment;
56  } else {
57  cleaned += '/';
58  cleaned += program[i];
59  state = NormalCode;
60 
61  // Checking for strings. We don't change or remove them but we have to report them
62  if ((program[i] == '\"') && ((i == 0) || (program[i - 1] != '\\'))) {
63  state = InString;
64  curString.originalStart = i;
65  curString.parsedStart = cleaned.size() - 1;
66  curString.type = StringPosition::String;
67  } else if ((program[i] == '\'') && ((i == 0) || (program[i - 1] != '\\'))) {
68  state = InCharacter;
69  curString.originalStart = i;
70  curString.parsedStart = cleaned.size() - 1;
71  curString.type = StringPosition::Character;
72  }
73  }
74  break;
75  case StartEndCComment:
76  state = InCComment;
77  if (program[i] == '/') {
78  state = NormalCode;
79  // Adding a whitespace for the cases of comments between two elements which should be separated
80  cleaned += ' ';
81  curComment.originalEnd = i;
82  curComment.parsedPosition = cleaned.size() - 1;
83  cpos.append(curComment);
84  } else if (program[i] == '*') {
85  state = StartEndCComment;
86  }
87  break;
88  case InCComment:
89  if (program[i] == '*') {
90  state = StartEndCComment;
91  }
92  break;
93  case InCppComment:
94  if ((program[i] == '\n') || (program[i] == '\r')) {
95  cleaned += program[i];
96  state = NormalCode;
97  curComment.originalEnd = i - 1;
98  curComment.parsedPosition = cleaned.size() - 1;
99  cpos.append(curComment);
100  }
101  break;
102  case InString:
103  cleaned += program[i];
104 
105  if ((program[i] == '"') && ((i == 0) || (program[i - 1] != '\\'))) {
106  state = NormalCode;
107  curString.originalEnd = i;
108  curString.parsedEnd = cleaned.size() - 1;
109  spos.append(curString);
110  }
111  break;
112  case InCharacter:
113  cleaned += program[i];
114 
115  // Here we don't check that there is only one character enclosed in '',
116  // the code won't compile anyway if there is more than one character
117  if ((program[i] == '\'') && ((i == 0) || (program[i - 1] != '\\'))) {
118  state = NormalCode;
119  curString.originalEnd = i;
120  curString.parsedEnd = cleaned.size() - 1;
121  spos.append(curString);
122  }
123  break;
124  case NormalCode:
125  if (program[i] == '/') {
126  state = FirstSlash;
127  curComment.originalStart = i;
128  } else {
129  cleaned += program[i];
130 
131  // Checking for strings. We don't change or remove them but we have to report them
132  if ((program[i] == '\"') && ((i == 0) || (program[i - 1] != '\\'))) {
133  state = InString;
134  curString.originalStart = i;
135  curString.parsedStart = cleaned.size() - 1;
136  curString.type = StringPosition::String;
137  } else if ((program[i] == '\'') && ((i == 0) || (program[i - 1] != '\\'))) {
138  state = InCharacter;
139  curString.originalStart = i;
140  curString.parsedStart = cleaned.size() - 1;
141  curString.type = StringPosition::Character;
142  }
143  }
144  break;
145  }
146  }
147 
148  // Whe have to check if we are still in a comment or string/character to add it
149  switch (state) {
150  case StartEndCComment:
151  case InCComment:
152  case InCppComment:
153  cleaned += ' ';
154  curComment.originalEnd = program.size() - 1;
155  curComment.parsedPosition = cleaned.size() - 1;
156  cpos.append(curComment);
157  break;
158  case InString:
159  case InCharacter:
160  curString.originalEnd = program.size() - 1;
161  curString.parsedEnd = cleaned.size() - 1;
162  spos.append(curString);
163  break;
164  default:
165  break;
166  }
167 
168  if (commentsPos != NULL) {
169  *commentsPos = cpos;
170  }
171  if (stringsPos != NULL) {
172  *stringsPos = spos;
173  }
174 
175  return cleaned;
176 }
177 
178 } // end namespace farsa