YSTest: Lexical.cpp 源文件

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
31 YSL_BEGIN_NAMESPACE(NPL)
32
33 LexicalAnalyzer::LexicalAnalyzer()
34 : esc(-1), ld(), cbuf(), qlist()
35 {}
36
37 void
38 LexicalAnalyzer::HandleEscape()
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
89 LexicalAnalyzer::PushEscape()
90 {
91 // cbuf += '^'; // test: 未转义。
92 yunseq(cbuf += '\\', escs[esc] = char());
93 yunseq(cbuf += escs, esc = -1);
94 }
95
96 void
97 LexicalAnalyzer::ParseByte(byte b)
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>
154 LexicalAnalyzer::Literalize() const
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
267 YSL_END_NAMESPACE(NPL)
268