Crevice  0.1
 All Classes Functions Variables Pages
Tokenizer.cc
1 /*
2  * File: Tokenizer.cc
3  *
4  * Copyright 2014 Heinrich Schuchardt <xypron.glpk@gmx.de>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <iostream>
20 #include <sstream>
21 #include <string>
22 #include "Tokenizer.h"
23 #include "Ustring.h"
24 
25 const std::string Tokenizer::SPEC_CHARS
26 ("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~");
27 
32  Ustring *ustr = NULL;
33  try {
34  ustr = new Ustring();
35  for (int i = 0;;) {
36  const Uchar u = str.charAt(i);
37  if (u <= ' ') {
38  // white space
39  ++i;
40  } else if (u == '#') {
41  // comment
42  while (str.charAt(i) != '\n') {
43  ++i;
44  }
45  } else if (u == '"') {
46  parseString(str, i);
47  } else if (u >= '0' && u <= '9') {
48  parseNumber(str, i);
49  } else if (u < 0x80 && SPEC_CHARS.find((char) u)
50  != std::string::npos) {
51  parseOperator(str, i);
52  continue;
53  } else {
54  parseId(str, i);
55  }
56  }
57  } catch (const Ustring::Error &e) {
58  }
59  delete ustr;
60 }
61 
66 }
67 
72 void Tokenizer::add(Token *tok) {
73  tokenlist.append(tok);
74 }
75 
81 void Tokenizer::parseBlockComment(Ustring &s, int &i) {
82  for (;;) {
83  Uchar u = s.charAt(++i);
84  if (u == '*') {
85  u = s.charAt(++i);
86  if (u == '/') {
87  return;
88  }
89  }
90  }
91 }
92 
98 void Tokenizer::parseId(Ustring &s, int &i) {
99  Ustring ustr;
100  Uchar u;
101  Token *t = NULL;
102 
103  for (;; ++i) {
104  u = s.charAt(i);
105  if (u <= ' ' || Tokenizer::SPEC_CHARS.find((char) u)
106  != std::string::npos) {
107  break;
108  }
109  ustr += u;
110  }
111 
112  t = new Token(Token::ID, ustr);
113  add(t);
114 }
115 
121 void Tokenizer::parseNumber(Ustring &s, int &i) {
122  Error error;
123  double value = 0;
124  bool expneg = false;
125  int exponent = 0;
126  bool dp = false;
127  int decimals = 0;
128  Uchar u0;
129  Token *t;
130 
131  for (;; ++i) {
132  u0 = s.charAt(i);
133  if (u0 == '.') {
134  Uchar u1 = s.charAt(++i);
135  --i;
136  if (u1 == '.') {
137  --i;
138  parseOperator(s, i);
139  return;
140  }
141  if (dp) {
142  throw error;
143  }
144  dp = true;
145  continue;
146  } else if (u0 < '0' || u0 > '9') {
147  break;
148  }
149  value *= 10.;
150  value += u0 - '0';
151  if (dp) {
152  ++decimals;
153  }
154  }
155  if (u0 == 'E' || u0 == 'e') {
156  u0 = s.charAt(++i);
157  if (u0 == '-') {
158  expneg = true;
159  u0 = s.charAt(++i);
160  } else if (u0 == '+') {
161  u0 = s.charAt(++i);
162  }
163  for (;; ++i) {
164  u0 = s.charAt(i);
165  if (u0 < '0' || u0 > '9') {
166  break;
167  }
168  exponent *= 10;
169  if (expneg) {
170  exponent -= u0 - '0';
171  } else {
172  exponent += u0 - '0';
173  }
174  }
175  }
176  exponent -= decimals;
177  if (expneg == false) {
178  for (int i = 0; i < exponent; ++i) {
179  value *= 10.;
180  }
181  } else {
182  for (int i = 0; i > exponent; --i) {
183  value /= 10.;
184  }
185  }
186 
187  t = new Token(value);
188  add(t);
189 }
190 
196 void Tokenizer::parseOperator(Ustring &s, int &i) {
197  Ustring ustr;
198  Uchar u0 = s.charAt(i);
199  Uchar u1 = s.charAt(++i);
200  Token *t;
201 
202  ustr += u0;
203  switch (u0) {
204  case '.':
205  if (u1 == '.') {
206  ustr += u1;
207  ++i;
208  } else if (u1 >= '0' && u1 <= '9') {
209  --i;
210  parseNumber(s, i);
211  return;
212  }
213  break;
214  case '/':
215  if (u1 == '*') {
216  parseBlockComment(s, i);
217  return;
218  }
219  break;
220  case ':':
221  case '=':
222  if (u1 == '=') {
223  ustr += u1;
224  ++i;
225  }
226  break;
227  case '|':
228  if (u1 == '|') {
229  ustr += u1;
230  ++i;
231  }
232  break;
233  case '&':
234  if (u1 == '&') {
235  ustr += u1;
236  ++i;
237  }
238  break;
239  }
240  t = new Token(Token::OPERATOR, ustr);
241  add(t);
242 }
243 
249 void Tokenizer::parseString(Ustring &s, int& i) {
250  Error error;
251  Ustring ustr;
252  Uchar u;
253  Token *t;
254 
255  for (;;) {
256  u = s.charAt(++i);
257  if (u < ' ') {
258  throw error;
259  } else if (u == '"') {
260  ++i;
261  break;
262  } else if (u == '\\') {
263  u = s.charAt(++i);
264  if (u < ' ') {
265  throw error;
266  }
267  switch (u) {
268  case '"':
269  ustr += '"';
270  break;
271  case '\\':
272  ustr += '\\';
273  break;
274  case 'n':
275  ustr += '\n';
276  break;
277  case 'r':
278  ustr += '\r';
279  break;
280  case 't':
281  ustr += '\t';
282  break;
283  case 'u':
284  {
285  Uchar e = 0;
286  for (int j = 0;; j++) {
287  u = s.charAt(++i);
288  if (u >= '0' && u <= '9') {
289  u -= '0';
290  } else if (u >= 'A' && u <= 'F') {
291  u -= 'A' - 10;
292  } else if (u >= 'a' && u <= 'f') {
293  u -= 'a' - 10;
294  } else if (u == ';') {
295  break;
296  } else {
297  throw error;
298  }
299  e <<= 4;
300  e += u;
301  if (e > 0x0010FFFFu) {
302  throw error;
303  }
304  }
305  ustr += e;
306  break;
307  }
308  case 'x':
309  {
310  Uchar e = 0;
311  for (int j = 0; j < 2; j++) {
312  u = s.charAt(++i);
313  if (u >= '0' && u <= '9') {
314  u -= '0';
315  } else if (u >= 'A' && u <= 'F') {
316  u -= 'A' - 10;
317  } else if (u >= 'a' && u <= 'f') {
318  u -= 'a' - 10;
319  } else {
320  throw error;
321  }
322  e <<= 4;
323  e += u;
324  }
325  ustr += e;
326  break;
327  }
328  default:
329  throw error;
330  }
331  } else {
332  ustr += u;
333  }
334  }
335 
336  t = new Token(Token::STRING, ustr);
337  add(t);
338 }
339 
345 std::string Tokenizer::toString() {
346  std::stringstream s;
347  for (TokenList::iterator it = tokenlist.begin();
348  it != tokenlist.end(); ++it) {
349  std::string str;
350  **it >> str;
351  str += " ";
352  s << str;
353  }
354  return s.str();
355 }