YSTest: Lexical.cpp 源文件

YSTest PreAlpha_b700_20160611 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

Lexical.cpp
浏览该文件的文档.
1 /*
2 © 2012-2016 FrankHB.
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/YModules.h"
29 #include YFM_NPL_Lexical
30 #include <ystdex/string.hpp> // for ystdex::get_mid;
31
32 namespace NPL
33 {
34
35 string
36 UnescapeContext::Done()
37 {
38 auto res(std::move(Prefix));
39
40 res += std::move(sequence);
41 Clear();
42 return res;
43 }
44
45
46 bool
47 HandleBackslashPrefix(char c, string& pfx)
48 {
49 if(c == '\\')
50 {
51 pfx = "\\";
52 return true;
53 }
54 return {};
55 }
56
57 bool
58 NPLUnescape(string& buf, const UnescapeContext& uctx, char ld)
59 {
60 const auto& escs(uctx.GetSequence());
61
62 if(uctx.IsHandling() && escs.length() == 1)
63 {
64 switch(escs[0])
65 {
66 case '\\':
67 buf += '\\';
68 break;
69 case 'a':
70 buf += '\a';
71 break;
72 case 'b':
73 if(!buf.empty())
74 buf.pop_back();
75 break;
76 case 'f':
77 buf += '\f';
78 break;
79 case 'n':
80 buf += '\n';
81 break;
82 case 'r':
83 buf += '\r';
84 break;
85 case 't':
86 buf += '\t';
87 break;
88 case 'v':
89 buf += '\v';
90 break;
91 case '\'':
92 case '"':
93 if(escs[0] == ld)
94 {
95 buf += ld;
96 break;
97 }
98 default:
99 return {};
100 }
101 return true;
102 }
103 return {};
104 }
105
106
107 LexicalAnalyzer::LexicalAnalyzer()
108 : unescape_context(), ld(), cbuf(), qlist()
109 {}
110
111 bool
112 LexicalAnalyzer::CheckEscape(byte b, Unescaper unescape)
113 {
114 if(!(b < 0x80))
115 {
116 // NOTE: Stop unescaping. The escaped sequence should have no
117 // multibyte characters.
118 if(unescape_context.IsHandling())
119 cbuf += unescape_context.Done();
120 cbuf += char(b);
121 }
122 else if(unescape_context.IsHandling())
123 {
124 unescape_context.Push(b);
125 if(unescape(cbuf, unescape_context, ld))
126 unescape_context.Clear();
127 else
128 cbuf += unescape_context.Done();
129 }
130 else
131 return {};
132 return true;
133 }
134
135 bool
136 LexicalAnalyzer::CheckLineConcatnater(char c, char concat, char newline)
137 {
138 if(line_concat == concat && c == newline)
139 {
140 if(!unescape_context.PopIf(concat))
141 {
142 auto& pfx(unescape_context.Prefix);
143
144 if(!pfx.empty() && pfx.back() == concat)
145 pfx.pop_back();
146 else if(!cbuf.empty() && cbuf.back() == line_concat)
147 cbuf.pop_back();
148 }
149 return true;
150 }
151 else if(c == concat)
152 line_concat = concat;
153 else
154 line_concat = {};
155 return {};
156 }
157
158 bool
159 LexicalAnalyzer::FilterForParse(char c, Unescaper unescape,
160 PrefixHandler prefix_handler)
161 {
162 return !(CheckLineConcatnater(c) || CheckEscape(byte(c), unescape)
163 || prefix_handler(c, unescape_context.Prefix));
164 }
165
166 void
167 LexicalAnalyzer::ParseByte(char c, Unescaper unescape,
168 PrefixHandler prefix_handler)
169 {
170 if(FilterForParse(c, unescape, prefix_handler))
171 switch(c)
172 {
173 case '\'':
174 case '"':
175 if(ld == char())
176 {
177 ld = c;
178 qlist.push_back(cbuf.size());
179 cbuf += c;
180 }
181 else if(ld == c)
182 {
183 ld = char();
184 cbuf += c;
185 qlist.push_back(cbuf.size());
186 }
187 else
188 cbuf += c;
189 case char():
190 break;
191 case ' ':
192 case '\f':
193 case '\n':
194 // case '\r':
195 case '\t':
196 case '\v':
197 if(ld == char())
198 {
199 cbuf += ' ';
200 break;
201 }
202 default:
203 cbuf += c;
204 }
205 }
206
207 void
208 LexicalAnalyzer::ParseQuoted(char c, Unescaper unescape,
209 PrefixHandler prefix_handler)
210 {
211 if(FilterForParse(c, unescape, prefix_handler))
212 cbuf += c;
213 }
214
215 list<string>
216 LexicalAnalyzer::Literalize() const
217 {
218 size_t i(0);
219 list<string> result;
220
221 std::for_each(qlist.cbegin(), qlist.cend(), [&](const size_t& s){
222 if(s != i)
223 {
224 result.push_back(cbuf.substr(i, s - i));
225 i = s;
226 }
227 });
228 result.push_back(cbuf.substr(i));
229 return result;
230 }
231
232
233 char
234 CheckLiteral(string_view sv) ynothrowv
235 {
236 YAssertNonnull(sv.data());
237 if(sv.size() > 1)
238 if(const char c = ystdex::get_quote_mark_nonstrict(sv))
239 {
240 if(c == '\'' || c == '"')
241 return c;
242 }
243 return {};
244 }
245
246 string_view
247 Deliteralize(string_view sv) ynothrowv
248 {
249 return CheckLiteral(sv) == char() ? sv : ystdex::get_mid(sv);
250 }
251
252 string
253 Escape(string_view sv)
254 {
255 YAssertNonnull(sv.data());
256
257 char last{};
258 string res;
259
260 res.reserve(sv.length());
261 for(char c : sv)
262 {
263 char unescaped{};
264
265 switch(c)
266 {
267 case '\a':
268 unescaped = 'a';
269 break;
270 case '\b':
271 unescaped = 'b';
272 break;
273 case '\f':
274 unescaped = 'f';
275 break;
276 case '\n':
277 unescaped = 'n';
278 break;
279 case '\r':
280 unescaped = 'r';
281 break;
282 case '\t':
283 unescaped = 't';
284 break;
285 case '\v':
286 unescaped = 'v';
287 break;
288 case '\'':
289 case '"':
290 unescaped = c;
291 }
292 if(last == '\\')
293 {
294 if(c == '\\')
295 {
296 yunseq(last = char(), res += '\\');
297 continue;
298 }
299 switch(c)
300 {
301 case 'a':
302 case 'b':
303 case 'f':
304 case 'n':
305 case 'r':
306 case 't':
307 case 'v':
308 case '\'':
309 case '"':
310 res += '\\';
311 }
312 }
313 if(unescaped == char())
314 res += c;
315 else
316 {
317 res += '\\';
318 res += unescaped;
319 unescaped = char();
320 }
321 last = c;
322 }
323 return res;
324 }
325
326 string
327 EscapeLiteral(string_view sv)
328 {
329 const char c(CheckLiteral(sv));
330 // TODO: Use %get_mid for %string_view.
331 auto content(Escape(c == char() ? sv : ystdex::get_mid(string(sv))));
332
333 if(!content.empty() && content.back() == '\\')
334 content += '\\';
335 return c == char() ? std::move(content) : ystdex::quote(content, c);
336 }
337
338 string
339 EscapeXML(string_view sv)
340 {
341 YAssertNonnull(sv.data());
342
343 string res;
344
345 res.reserve(sv.length());
346 for(char c : sv)
347 switch(c)
348 {
349 case '\0':
350 YTraceDe(YSLib::Warning, "Invalid character '#x%X' found, ignored.",
351 unsigned(c));
352 break;
353 case '&':
354 res += "&amp;";
355 break;
356 case '<':
357 res += "&lt;";
358 break;
359 case '>':
360 res += "&gt;";
361 break;
362 default:
363 res += c;
364 }
365 return res;
366 }
367
368 string
369 Literalize(string_view sv, char c)
370 {
371 return CheckLiteral(sv) == char() && c != char()
372 ? ystdex::quote(string(sv), c) : string(sv);
373 }
374
375
376 list<string>
377 Decompose(string_view src)
378 {
379 YAssertNonnull(src.data());
380
381 list<string> dst;
382
383 ystdex::split_l(src.cbegin(), src.cend(), IsDelimeter,
384 [&](const char* b, const char* e) YB_NONNULL(1, 2){
385 YAssert(e >= b, "Invalid split result found.");
386
387 string_view sv(b, size_t(e - b));
388
389 YAssert(!sv.empty(), "Null token found.");
390 if(IsGraphicalDelimeter(*b))
391 {
392 dst.push_back({sv.front()});
393 sv.remove_prefix(1);
394 }
395 ystdex::trim(sv);
396 if(!sv.empty())
397 dst.push_back(string(sv));
398 });
399 return dst;
400 }
401
402 list<string>
403 Tokenize(const list<string>& src)
404 {
405 list<string> dst;
406
407 for(const auto& str : src)
408 if(!str.empty())
409 {
410 if(str[0] != '\'' && str[0] != '"')
411 dst.splice(dst.end(), Decompose(str));
412 else
413 dst.push_back(str);
414 }
415 return dst;
416 }
417
418 } // namespace NPL;
419
NPL::UnescapeContext::Prefix
string Prefix
转义序列前缀。
Definition: Lexical.h:63
NPL::IsGraphicalDelimeter
yconstfn bool IsGraphicalDelimeter(char c)
判断是否为 NPL 图形分隔符。
Definition: Lexical.h:305
ystdex::string_view
basic_string_view< char > string_view
Definition: string_view.hpp:415
platform::containers::string
basic_string< char > string
Definition: Container.h:101
NPL::Decompose
YF_API list< string > Decompose(string_view)
分解字符串为记号。
Definition: Lexical.cpp:377
platform::Descriptions::Warning
Definition: YCommon.h:157
YSLib::Text::buf
const char * buf
Definition: TextFile.h:77
NPL::UnescapeContext::sequence
string sequence
有效转义序列。
Definition: Lexical.h:67
NPL::Escape
YF_API string Escape(string_view)
编码转义字符串：替换指定字符串中的可转义字符为转义序列。
Definition: Lexical.cpp:253
ystdex::trim
_tString && trim(_tString &&str, typename string_traits< _tString >::value_type c)
删除字符串中指定的连续前缀与后缀字符。
Definition: string.hpp:649
NPL::LexicalAnalyzer::FilterForParse
bool FilterForParse(char, Unescaper, PrefixHandler)
Definition: Lexical.cpp:159
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:109
ystdex::get_quote_mark_nonstrict
string_traits< _tString >::value_type get_quote_mark_nonstrict(const _tString &str)
取相同的前缀和后缀元素。
Definition: string.hpp:726
ynothrowv
#define ynothrowv
YSLib 无异常抛出保证验证：有条件地使用无异常抛出规范。
Definition: ydef.h:760
YAssert
#define YAssert(_expr, _msg)
Definition: cassert.h:105
NPL::LexicalAnalyzer::ParseQuoted
void ParseQuoted(char, Unescaper=NPLUnescape, PrefixHandler=HandleBackslashPrefix)
解析单个字面量字符并添加至字符解析结果：反转义以外无视边界字符。
Definition: Lexical.cpp:208
NPL::Tokenize
YF_API list< string > Tokenize(const list< string > &)
记号化：提取字符串列表中的记号。
Definition: Lexical.cpp:403
NPL::UnescapeContext
反转义上下文。
Definition: Lexical.h:59
NPL::EscapeXML
YF_API string EscapeXML(string_view)
编码 XML 字符串。
Definition: Lexical.cpp:339
CHRLib::c
c
Definition: CharacterProcessing.h:81
NPL::UnescapeContext::PopIf
PopIf
Definition: Lexical.h:91
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:305
NPL::HandleBackslashPrefix
YF_API bool HandleBackslashPrefix(char, string &)
设置反斜杠转义前缀：当输入 '\' 时设置前缀为 "\\" 。
Definition: Lexical.cpp:47
NPL::LexicalAnalyzer::qlist
vector< size_t > qlist
字符解析中间结果中非转义的引号出现的位置的有序列表。
Definition: Lexical.h:189
NPL::LexicalAnalyzer::unescape_context
UnescapeContext unescape_context
反转移上下文：储存反转义中间结果。
Definition: Lexical.h:175
NPL::IsDelimeter
yconstfn bool IsDelimeter(char c)
判断是否为 NPL 分隔符。
Definition: Lexical.h:317
NPL::dst
YF_API const char src const string const char * dst
Definition: Dependency.h:93
NPL::LexicalAnalyzer::Literalize
list< string > Literalize() const
根据中间结果取字符串列表。
Definition: Lexical.cpp:216
YAssertNonnull
#define YAssertNonnull(_expr)
Definition: cassert.h:114
NPL::LexicalAnalyzer::cbuf
string cbuf
字符解析中间结果。
Definition: Lexical.h:184
YModules.h
ystdex::split_l
_tIn split_l(_tIn b, _tIn e, _fPred is_delim, _fInsert insert)
以指定分隔符分割保留起始分隔符的序列。
Definition: algorithm.hpp:257
NPL::Deliteralize
YF_API string_view Deliteralize(string_view) ynothrowv
去除字面量边界分隔符。
Definition: Lexical.cpp:247
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:996
NPL::LexicalAnalyzer::ld
char ld
字面分隔符状态：表示正在处理字面量中的有效字符。
Definition: Lexical.h:180
YSLib::Text::str
const char const char * str
Definition: TextFile.h:77
NPL
Definition: NPL/Configuration.h:34
NPL::LexicalAnalyzer::PrefixHandler
std::function< bool(char, string &)> PrefixHandler
转移序列前缀处理器。
Definition: Lexical.h:154
NPL::LexicalAnalyzer::LexicalAnalyzer
LexicalAnalyzer()
Definition: Lexical.cpp:107
NPL::YB_NONNULL
YF_API YB_NONNULL(1, 2) void InstallFile(const char *
安装文件：复制单个文件。
NPL::LexicalAnalyzer::CheckLineConcatnater
const string cbuf DefGetter(const ynothrow, const vector< size_t > &, Quotes, qlist) private bool CheckLineConcatnater(char, char= '\\', char= '\n')
Definition: Lexical.h:206
NPL::Literalize
YF_API string Literalize(string_view, char= '"')
修饰字符串为字面量。
Definition: Lexical.cpp:369
ystdex::get_mid
_tString get_mid(const _tString &str, typename _tString::size_type l=1)
取删除前缀和后缀的子字符串。
Definition: string.hpp:769
YSLib::i
return i
Definition: YCoreUtilities.h:176
ystdex::byte
unsigned char byte
字节类型。
Definition: ydef.h:808
NPL::NPLUnescape
YF_API bool NPLUnescape(string &, const UnescapeContext &, char)
NPL 转义匹配算法。
Definition: Lexical.cpp:58
string.hpp
ISO C++ 标准字符串扩展。
NPL::EscapeLiteral
YF_API string EscapeLiteral(string_view)
编码转义字符串字面量。
Definition: Lexical.cpp:327
NPL::LexicalAnalyzer::Unescaper
std::function< bool(string &, const UnescapeContext &, char)> Unescaper
指定匹配转义序列的反转义算法：解析转义序列并按需修改指定缓存。
Definition: Lexical.h:162
NPL::UnescapeContext::Push
char c Push
Definition: Lexical.h:94
YSLib::char
char
Definition: ValueNode.h:851
ystdex::concat
void concat(_tCon &con, _tIn first, _tIn last)
插入元素到容器末尾。
Definition: container.hpp:435
NPL::LexicalAnalyzer::line_concat
char line_concat
指示当前续行符状态。
Definition: Lexical.h:169
NPL::LexicalAnalyzer::ParseByte
void ParseByte(char, Unescaper=NPLUnescape, PrefixHandler=HandleBackslashPrefix)
解析单个字符并添加至字符解析结果。
Definition: Lexical.cpp:167
ystdex::quote
_tString quote(const _tString &str, typename string_traits< _tString >::value_type c=typename string_traits< _tString >::value_type('"'))
取添加前缀和后缀的字符串。
Definition: string.hpp:741
NPL::CheckLiteral
YF_API char CheckLiteral(string_view) ynothrowv
检查指定字符串是否为字面量。
Definition: Lexical.cpp:234
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
NPL::UnescapeContext::IsHandling
!Prefix IsHandling
Definition: Lexical.h:78