LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
expr_parsing.cpp
浏览该文件的文档.
6
7#include <cctype>
8#include <exception>
9#include <stdexcept>
10#include <utility>
11
12namespace LMCAS::expr_detail {
13
15 skip_space();
16 if (eof()) {
17 return fail("empty expression");
18 }
19 auto result = parse_logical_or();
20 if (!result) { return result; }
21 skip_space();
22 if (!eof()) {
23 return fail("unexpected token '" + std::string(1, peek()) + "'");
24 }
25 return result;
26}
27
28bool ExprParser::eof() const noexcept { return pos_ >= source_.size(); }
29
30char ExprParser::peek() const noexcept {
31 return eof() ? '\0' : source_[pos_];
32}
33
34bool ExprParser::match(char c) {
35 skip_space();
36 if (peek() != c) { return false; }
37 ++pos_;
38 return true;
39}
40
41bool ExprParser::match_text(const char* text) {
42 skip_space();
43 const std::size_t start = pos_;
44 for (const char* p = text; *p; ++p) {
45 if (pos_ >= source_.size() || source_[pos_] != *p) {
46 pos_ = start;
47 return false;
48 }
49 ++pos_;
50 }
51 return true;
52}
53
54bool ExprParser::match_keyword(const char* text) {
55 skip_space();
56 const std::size_t start = pos_;
57 if (!match_text(text)) { return false; }
58 if (is_ident_continue(static_cast<unsigned char>(peek()))) {
59 pos_ = start;
60 return false;
61 }
62 return true;
63}
64
65void ExprParser::skip_space() noexcept {
66 while (!eof() &&
67 std::isspace(static_cast<unsigned char>(source_[pos_]))) {
68 ++pos_;
69 }
70}
71
72ExprResult ExprParser::fail(std::string message) const {
74 std::move(message) + " at byte " + std::to_string(pos_),
76}
77
78bool ExprParser::is_ident_start(unsigned char c) noexcept {
79 return std::isalpha(c) || c == '_' || c >= 0x80;
80}
81
82bool ExprParser::is_ident_continue(unsigned char c) noexcept {
83 return std::isalnum(c) || c == '_' || c >= 0x80;
84}
85
87 auto lhs = parse_logical_and();
88 if (!lhs) { return lhs; }
89 while (match_keyword("or")) {
90 auto rhs = parse_logical_and();
91 if (!rhs) { return rhs; }
92 lhs = logical(lhs.value(), rhs.value(), LogicalNode::Op::Or);
93 if (!lhs) { return lhs; }
94 }
95 return lhs;
96}
97
99 auto lhs = parse_logical_not();
100 if (!lhs) { return lhs; }
101 while (match_keyword("and")) {
102 auto rhs = parse_logical_not();
103 if (!rhs) { return rhs; }
104 lhs = logical(lhs.value(), rhs.value(), LogicalNode::Op::And);
105 if (!lhs) { return lhs; }
106 }
107 return lhs;
108}
109
111 if (match_keyword("not") || match('!')) {
112 auto operand = parse_logical_not();
113 if (!operand) { return operand; }
114 return logical(operand.value(), nullptr, LogicalNode::Op::Not);
115 }
116 return parse_membership();
117}
118
120 auto lhs = parse_equality();
121 if (!lhs) { return lhs; }
122 if (match_keyword("in")) {
123 auto rhs = parse_equality();
124 if (!rhs) { return rhs; }
125 return membership(lhs.value(), rhs.value(), false);
126 }
127 const auto save = pos_;
128 if (match_keyword("not")) {
129 if (match_keyword("in")) {
130 auto rhs = parse_equality();
131 if (!rhs) { return rhs; }
132 return membership(lhs.value(), rhs.value(), true);
133 }
134 pos_ = save;
135 }
136 return lhs;
137}
138
140 auto lhs = parse_relational();
141 if (!lhs) { return lhs; }
142 while (true) {
144 if (match_text("==")) {
146 } else if (match_text("!=")) {
148 } else {
149 return lhs;
150 }
151 auto rhs = parse_relational();
152 if (!rhs) { return rhs; }
153 lhs = relational(lhs.value(), rhs.value(), op);
154 if (!lhs) { return lhs; }
155 }
156}
157
159 auto lhs = parse_additive();
160 if (!lhs) { return lhs; }
161 while (true) {
163 if (match_text("<=")) {
165 } else if (match_text(">=")) {
167 } else if (match('<')) {
169 } else if (match('>')) {
171 } else {
172 return lhs;
173 }
174 auto rhs = parse_additive();
175 if (!rhs) { return rhs; }
176 lhs = relational(lhs.value(), rhs.value(), op);
177 if (!lhs) { return lhs; }
178 }
179}
180
182 auto lhs = parse_multiplicative();
183 if (!lhs) { return lhs; }
184 while (true) {
185 if (match('+')) {
186 auto rhs = parse_multiplicative();
187 if (!rhs) { return rhs; }
188 lhs = add(lhs.value(), rhs.value());
189 } else if (match('-')) {
190 auto rhs = parse_multiplicative();
191 if (!rhs) { return rhs; }
192 lhs = sub(lhs.value(), rhs.value());
193 } else {
194 return lhs;
195 }
196 if (!lhs) { return lhs; }
197 }
198}
199
201 auto lhs = parse_power();
202 if (!lhs) { return lhs; }
203 while (true) {
204 if (match_text("**")) {
205 return fail("operator '**' is not supported; use '^'");
206 } else if (match('*')) {
207 auto rhs = parse_power();
208 if (!rhs) { return rhs; }
209 lhs = mul(lhs.value(), rhs.value());
210 } else if (match('/')) {
211 auto rhs = parse_power();
212 if (!rhs) { return rhs; }
213 lhs = div(lhs.value(), rhs.value());
214 } else {
215 return lhs;
216 }
217 if (!lhs) { return lhs; }
218 }
219}
220
222 auto base = parse_unary();
223 if (!base) { return base; }
224 if (match_text("**")) {
225 return fail("operator '**' is not supported; use '^'");
226 }
227 if (match('^')) {
228 auto exponent = parse_power();
229 if (!exponent) { return exponent; }
230 return pow(base.value(), exponent.value());
231 }
232 return base;
233}
234
236 if (match('+')) { return parse_unary(); }
237 if (match('-')) {
238 auto operand = parse_unary();
239 if (!operand) { return operand; }
240 return neg(operand.value());
241 }
242 return parse_primary();
243}
244
246 skip_space();
247 if (match('(')) {
248 auto inner = parse_logical_or();
249 if (!inner) { return inner; }
250 if (match(',')) {
251 auto rhs = parse_logical_or();
252 if (!rhs) { return rhs; }
253 if (!match(')')) { return fail("expected ')' after interval"); }
254 return interval(inner.value(), rhs.value(), false, false);
255 }
256 if (!match(')')) { return fail("expected ')'"); }
257 return inner;
258 }
259 if (match('{')) {
260 return parse_set_literal();
261 }
262 if (match('[')) {
263 return parse_interval_literal(true);
264 }
265 if (std::isdigit(static_cast<unsigned char>(peek())) || peek() == '.') {
266 return parse_number();
267 }
268 if (is_ident_start(static_cast<unsigned char>(peek()))) {
270 }
271 return fail("expected expression");
272}
273
275 std::vector<ExprPtr> elements;
276 if (!match('}')) {
277 while (true) {
278 auto element = parse_logical_or();
279 if (!element) { return element; }
280 elements.push_back(element.value());
281 if (match('}')) break;
282 if (!match(',')) { return fail("expected ',' or '}' in set literal"); }
283 }
284 }
285 return finite_set(elements);
286}
287
289 auto lower = parse_logical_or();
290 if (!lower) { return lower; }
291 if (!match(',')) { return fail("expected ',' in interval literal"); }
292 auto upper = parse_logical_or();
293 if (!upper) { return upper; }
294 bool upper_closed;
295 if (match(']')) {
296 upper_closed = true;
297 } else if (match(')')) {
298 upper_closed = false;
299 } else {
300 return fail("expected ']' or ')' after interval literal");
301 }
302 return interval(lower.value(), upper.value(), lower_closed, upper_closed);
303}
304
306 skip_space();
307 const std::size_t start = pos_;
308 bool saw_digit = false;
309 while (std::isdigit(static_cast<unsigned char>(peek()))) {
310 saw_digit = true;
311 ++pos_;
312 }
313 if (peek() == '.') {
314 ++pos_;
315 while (std::isdigit(static_cast<unsigned char>(peek()))) {
316 saw_digit = true;
317 ++pos_;
318 }
319 }
320 if (!saw_digit) { return fail("invalid number literal"); }
321 if (peek() == 'e' || peek() == 'E') {
322 ++pos_;
323 if (peek() == '+' || peek() == '-') ++pos_;
324 bool saw_exp_digit = false;
325 while (std::isdigit(static_cast<unsigned char>(peek()))) {
326 saw_exp_digit = true;
327 ++pos_;
328 }
329 if (!saw_exp_digit) { return fail("invalid number exponent"); }
330 }
331 try {
332 return rational(Rational(source_.substr(start, pos_ - start)));
333 } catch (const std::bad_alloc&) {
335 "number literal allocation failed",
337 } catch (const std::invalid_argument& error) {
339 CasErrc::ParseError, error.what(), kParseOperation);
340 } catch (const std::out_of_range& error) {
342 CasErrc::ParseError, error.what(), kParseOperation);
343 } catch (const std::exception& error) {
346 }
347}
348
350 skip_space();
351 const std::size_t start = pos_;
352 if (!is_ident_start(static_cast<unsigned char>(peek()))) { return {}; }
353 ++pos_;
354 while (is_ident_continue(static_cast<unsigned char>(peek()))) ++pos_;
355 return source_.substr(start, pos_ - start);
356}
357
359 skip_space();
360 const auto start = pos_;
361 while (!eof() && peek() != ')' &&
362 !std::isspace(static_cast<unsigned char>(peek()))) ++pos_;
363 const std::string_view token(source_.data() + start, pos_ - start);
364 if (!match(')')) return fail("expected ')' after approximate decimal");
366 if (!value) return fail(value.error().message);
367 return approx_real(value.value());
368}
369
371 if (name == "approx") return parse_approx_literal();
372 std::vector<ExprPtr> arguments;
373 bool closed = match(')');
374 if (!closed) {
375 do {
376 auto argument = parse_logical_or();
377 if (!argument) {
378 return argument;
379 }
380 arguments.push_back(argument.value());
381 if (match(')')) {
382 closed = true;
383 break;
384 }
385 } while (match(','));
386 }
387 if (!closed) {
388 return fail("expected ')'");
389 }
390 return apply_function(name, arguments);
391}
392
394 auto name = parse_identifier();
395 if (name.empty()) {
396 return fail("expected identifier");
397 }
398 skip_space();
399 if (match('(')) {
400 return parse_call(name);
401 }
402 if (name == "pi" || name == "π") {
403 return pi();
404 }
405 if (name == "e") {
406 return e();
407 }
408 if (name == "phi") {
409 return phi();
410 }
412 return imaginary_unit();
413 }
414 return sym(name);
415}
416
417}
418
419namespace LMCAS {
420
423
424ExprResult parse_expr(const std::string& source) {
426 return parse_expr(source, context);
427}
428
429ExprResult parse_expr(const std::string& source,
431 auto input_budget =
432 context.require_input_bytes(source.size(), kParseOperation);
433 if (!input_budget) {
434 return ExprResult::failure(input_budget.error());
435 }
436 try {
437 return ExprParser(source).parse();
438 } catch (const std::bad_alloc&) {
440 "expression parse allocation failed",
442 } catch (const std::exception& error) {
445 }
446}
447
448}
static bool is_ident_continue(unsigned char c) noexcept
static bool is_ident_start(unsigned char c) noexcept
ExprResult parse_logical_and()
ExprResult parse_logical_or()
char peek() const noexcept
ExprResult parse_multiplicative()
void skip_space() noexcept
ExprResult parse_approx_literal()
bool match_keyword(const char *text)
ExprParser(std::string source)
ExprResult parse_identifier_or_call()
bool match_text(const char *text)
ExprResult parse_call(const std::string &name)
std::string parse_identifier()
bool eof() const noexcept
ExprResult fail(std::string message) const
ExprResult parse_interval_literal(bool lower_closed)
@ Not
一元逻辑非,right 为 nullptr。
static Result failure(CasErrc code, std::string message, std::string operation={})
static bool is_ident_continue(unsigned char c) noexcept
static bool is_ident_start(unsigned char c) noexcept
ExprResult interval(const ExprPtr &lower, const ExprPtr &upper, bool lower_closed, bool upper_closed)
ExprResult logical(const ExprPtr &lhs, const ExprPtr &rhs, LogicalNode::Op op)
ExprResult apply_function(const std::string &name, const std::vector< ExprPtr > &arguments)
bool match_keyword(const char *text)
ExprResult finite_set(const std::vector< ExprPtr > &elements)
ExprResult relational(const ExprPtr &lhs, const ExprPtr &rhs, RelationOp op)
ExprResult parse_call(const std::string &name)
ExprResult membership(const ExprPtr &element, const ExprPtr &set, bool negated)
ExprResult fail(std::string message) const
ExprResult parse_interval_literal(bool lower_closed)
bool is_imaginary_unit_name(const std::string &name)
Result< double > parse_finite_decimal(std::string_view token)
ExprResult expression_failure(CasErrc code, std::string message, const char *operation)
constexpr const char * kParseOperation
ExprResult pow(const ExprPtr &base, const ExprPtr &exponent, ComputationContext &context)
const ExprPtr & element
ExprResult imaginary_unit()
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr upper
ExprResult e()
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult neg(const ExprPtr &expression, ComputationContext &context)
ExprResult approx_real(double value)
ExprResult sub(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
const ExprPtr & lower
ExprResult div(const ExprPtr &numerator, const ExprPtr &denominator, ComputationContext &context)
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
const VectorField const VectorField & c
Result< ExprPtr > ExprResult
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
RelationOp
Stable relational operator used by public APIs.
const ExprPtr RelationOp op
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr bool lower_closed
const ExprPtr & exponent
ExprResult parse_expr(const std::string &source)
ExprResult sym(const std::string &name)
constexpr const char * kParseOperation
ExprResult pi()
const std::string const ExprPtr & value
const ExprPtr & rhs
ExprResult phi()
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr bool bool upper_closed
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name
ExprResult rational(const Rational &value)