YSTest  PreAlpha_b400_20130424
The YSLib Test Project
 全部  命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义  
Lexical.cpp
浏览该文件的文档.
1 /*
2  Copyright (C) by Franksoft 2012.
3 
4  This file is part of the YSLib project, and may only be used,
5  modified, and distributed under the terms of the YSLib project
6  license, LICENSE.TXT. By continuing to use, modify, or distribute
7  this file you indicate that you have read the license and
8  understand and accept it fully.
9 */
10 
28 #include "NPL/Lexical.h"
29 #include <ystdex/string.hpp> // for ystdex::get_mid;
30 
32 
34  : esc(-1), ld(), cbuf(), qlist()
35 {}
36 
37 void
39 {
40  YAssert(esc <= MaxEscapeLength, "Escape sequence is too long.");
41 
42  if(esc == 1)
43  {
44  switch(*escs)
45  {
46  case '\\':
47  cbuf += '\\';
48  break;
49  case 'a':
50  cbuf += '\a';
51  break;
52  case 'b':
53  if(!cbuf.empty())
54  cbuf.pop_back();
55  break;
56  case 'f':
57  cbuf += '\f';
58  break;
59  case 'n':
60  cbuf += '\n';
61  break;
62  case 'r':
63  cbuf += '\r';
64  break;
65  case 't':
66  cbuf += '\t';
67  break;
68  case 'v':
69  cbuf += '\v';
70  break;
71  case '\'':
72  case '"':
73  if(*escs == ld)
74  {
75  cbuf += ld;
76  break;
77  }
78  default:
79  PushEscape();
80  return;
81  }
82  esc = -1;
83  }
84  else
85  PushEscape();
86 }
87 
88 void
90 {
91 // cbuf += '^'; // test: 未转义。
92  yunseq(cbuf += '\\', escs[esc] = char());
93  yunseq(cbuf += escs, esc = -1);
94 }
95 
96 void
98 {
99  if(!(b < 0x80))
100  {
101  //停止转义(转义序列不接受多字节字符)。
102  if(esc != size_t(-1))
103  PushEscape();
104  cbuf += char(b);
105  }
106  else if(esc != size_t(-1))
107  {
108  escs[esc++] = b;
109  HandleEscape();
110  }
111  else if(b == '\\' && ld != char())
112  esc = 0;
113  else
114  {
115  switch(b)
116  {
117  case '\'':
118  case '"':
119  if(ld == char())
120  {
121  // cbuf += '{'; // test;
122  ld = b;
123  qlist.push_back(cbuf.size());
124  cbuf += char(b);
125  }
126  else if(ld == b)
127  {
128  // cbuf += '}'; // test;
129  ld = char();
130  cbuf += char(b);
131  qlist.push_back(cbuf.size());
132  }
133  else
134  cbuf += char(b);
135  break;
136  case ' ':
137  case '\f':
138  case '\n':
139  // case '\r':
140  case '\t':
141  case '\v':
142  if(ld == char())
143  {
144  cbuf += ' ';
145  break;
146  }
147  default:
148  cbuf += char(b);
149  }
150  }
151 }
152 
153 list<string>
155 {
156  size_t i(0);
157  list<string> result;
158 
159  std::for_each(qlist.cbegin(), qlist.cend(), [&](const size_t& s){
160  if(s != i)
161  {
162  result.push_back(cbuf.substr(i, s - i));
163  i = s;
164  }
165  });
166  result.push_back(cbuf.substr(i));
167  return result;
168 }
169 
170 
171 char
172 CheckLiteral(const string& str)
173 {
174  if(str.size() < 2)
175  return char();
176  if(str.front() == '\'' && str.back() == '\'')
177  return '\'';
178  if(str.front() == '"' && str.back() == '"')
179  return '"';
180  return char();
181 }
182 
183 string
184 Deliteralize(const string& str)
185 {
186  return CheckLiteral(str) == char() ? str : ystdex::get_mid(str);
187 }
188 
189 string
190 MakeEscape(const string& str)
191 {
192  string res;
193 
194  for(char c : str)
195  switch(c)
196  {
197  case '\a':
198  res += "\\a";
199  break;
200  case '\b':
201  res += "\\b";
202  break;
203  case '\f':
204  res += "\\f";
205  break;
206  case '\n':
207  res += "\\n";
208  break;
209  case '\r':
210  res += "\\r";
211  break;
212  case '\t':
213  res += "\\t";
214  break;
215  case '\v':
216  res += "\\v";
217  break;
218  default:
219  res += c;
220  }
221  if(!str.empty() && str.back() == '\\')
222  res += "\\";
223  return std::move(res);
224 }
225 
226 
227 list<string>
228 Decompose(const string& src_str)
229 {
230  list<string> dst;
231 
232  ystdex::split(src_str.cbegin(), src_str.cend(), IsDelimeter, [&](
233  string::const_iterator b, string::const_iterator e){
234  string str(b, e);
235 
236  YAssert(!str.empty(), "Null token found.");
237 
238  if(IsGraphicalDelimeter(*b))
239  {
240  dst.push_back(str.substr(0, 1));
241  str.erase(0, 1);
242  }
243  // TODO: Optimize using %string_ref.
244  ystdex::trim(str);
245  if(!str.empty())
246  dst.push_back(std::move(str));
247  });
248  return dst;
249 }
250 
251 list<string>
252 Tokenize(const list<string>& src)
253 {
254  list<string> dst;
255 
256  for(const auto& str : src)
257  if(!str.empty())
258  {
259  if(str[0] != '\'' && str[0] != '"')
260  dst.splice(dst.end(), Decompose(str));
261  else
262  dst.push_back(str);
263  }
264  return dst;
265 }
266 
268