Bertini 2 d882924 (2026-10-06 19:56 UTC)
Numerical algebraic geometry library (C++ core)
Loading...
Searching...
No Matches
qi_files.hpp
Go to the documentation of this file.
1//This file is part of Bertini 2.
2//
3//bertini2/nag_algorithms/zero_dim_solve.hpp is free software: you can redistribute it and/or modify
4//it under the terms of the GNU General Public License as published by
5//the Free Software Foundation, either version 3 of the License, or
6//(at your option) any later version.
7//
8//bertini2/io/parsing/qi_files.hpp is distributed in the hope that it will be useful,
9//but WITHOUT ANY WARRANTY; without even the implied warranty of
10//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11//GNU General Public License for more details.
12//
13//You should have received a copy of the GNU General Public License
14//along with bertini2/io/parsing/qi_files.hpp. If not, see <http://www.gnu.org/licenses/>.
15//
16// Copyright(C) Bertini2 Development Team
17//
18// See <http://www.gnu.org/licenses/> for a copy of the license,
19// as well as COPYING. Bertini2 is provided with permitted
20// additional terms in the b2/licenses/ directory.
21
22
28
29#pragma once
30
32#define BOOST_SPIRIT_USE_PHOENIX_V3 1
33
34#include <boost/fusion/adapted.hpp>
35#include <boost/fusion/include/adapted.hpp>
36
37#include <boost/spirit/include/qi.hpp>
38#include <boost/phoenix.hpp>
39
40
41#include <boost/spirit/include/qi.hpp>
42#include <boost/spirit/include/qi_core.hpp>
43#include <boost/phoenix/core.hpp>
44#include <boost/phoenix/operator.hpp>
45#include <boost/fusion/include/std_pair.hpp>
46
47#include <boost/phoenix/bind/bind_function.hpp>
48#include <boost/phoenix/object/construct.hpp>
49#include <boost/bind/bind.hpp>
50
51#include <boost/fusion/adapted/adt/adapt_adt.hpp>
52#include <boost/fusion/include/adapt_adt.hpp>
53
54#include <boost/spirit/include/support_istream_iterator.hpp>
55
56#include <algorithm>
57#include <iostream>
58#include <sstream>
59#include <stdexcept>
60#include <cctype>
61#include <cstring>
62#include <string>
63
65
66namespace bertini {
67namespace parsing {
68namespace classic {
69
74inline void StripUTF8BOM(std::string& s)
75{
76 if (s.size() >= 3 &&
77 static_cast<unsigned char>(s[0]) == 0xEF &&
78 static_cast<unsigned char>(s[1]) == 0xBB &&
79 static_cast<unsigned char>(s[2]) == 0xBF)
80 {
81 s.erase(0, 3);
82 }
83}
84
91inline void StripClassicComments(std::string& s)
92{
93 std::string out;
94 out.reserve(s.size());
95 bool in_comment = false;
96 for (char c : s)
97 {
98 if (c == '\n')
99 {
100 in_comment = false;
101 out.push_back(c);
102 }
103 else if (in_comment)
104 continue;
105 else if (c == '%')
106 in_comment = true;
107 else
108 out.push_back(c);
109 }
110 s.swap(out);
111}
112
125inline void StripClassicFileWrappers(std::string& s)
126{
127 auto skip_ws = [](std::string const& t, size_t i) {
128 while (i < t.size() && std::isspace(static_cast<unsigned char>(t[i]))) ++i;
129 return i;
130 };
131 // case-insensitive check for `word` at position i, followed by a non-identifier char
132 auto keyword_at = [](std::string const& t, size_t i, char const* word) {
133 size_t n = std::strlen(word);
134 if (i + n > t.size()) return false;
135 for (size_t k = 0; k < n; ++k)
136 if (std::toupper(static_cast<unsigned char>(t[i+k])) != word[k]) return false;
137 if (i + n < t.size())
138 {
139 unsigned char c = static_cast<unsigned char>(t[i+n]);
140 if (std::isalnum(c) || c=='_') return false;
141 }
142 return true;
143 };
144
145 size_t i = skip_ws(s, 0);
146
147 // a leading CONFIG section, if present, runs to its first END;
148 if (keyword_at(s, i, "CONFIG"))
149 {
150 size_t e = s.find("END;", i);
151 if (e == std::string::npos)
152 return; // malformed; let the grammar report it
153 i = skip_ws(s, e + 4);
154 }
155
156 // an INPUT section wrapper, if present: drop the keyword and the matching trailing END;
157 if (keyword_at(s, i, "INPUT"))
158 {
159 size_t body = skip_ws(s, i + 5);
160 size_t e = s.rfind("END;");
161 if (e == std::string::npos || e < body)
162 return; // malformed; let the grammar report it
163 s = s.substr(body, e - body);
164 return;
165 }
166
167 if (i != 0)
168 s = s.substr(i);
169}
170
172inline std::string FormatParseError(
173 std::string::const_iterator begin,
174 std::string::const_iterator end,
175 std::string::const_iterator err_pos,
176 boost::spirit::info const& what,
177 std::string const& parser_name)
178{
179 int line = 1 + (int)std::count(begin, err_pos, '\n');
180 auto rev = std::find(std::make_reverse_iterator(err_pos),
181 std::make_reverse_iterator(begin), '\n');
182 int col = 1 + (int)std::distance(rev.base(), err_pos);
183
184 std::string remaining(err_pos, end);
185 if (remaining.size() > 60)
186 remaining = remaining.substr(0, 60) + "...";
187 if (remaining.empty())
188 remaining = "<end of input>";
189
190 std::ostringstream oss;
191 oss << "[" << parser_name << "] parse error at line " << line
192 << ", col " << col << ":\n"
193 << " expected: " << what << "\n"
194 << " found: \"" << remaining << "\"\n";
195 return oss.str();
196}
197
200 std::string::const_iterator begin,
201 std::string::const_iterator end,
202 std::string::const_iterator err_pos,
203 boost::spirit::info const& what,
204 std::string const& parser_name)
205{
206 auto msg = FormatParseError(begin, end, err_pos, what, parser_name);
207 std::cerr << msg;
208 throw std::runtime_error(msg);
209}
210
211} // namespace classic
212} // namespace parsing
213} // namespace bertini
void ReportParseError(std::string::const_iterator begin, std::string::const_iterator end, std::string::const_iterator err_pos, boost::spirit::info const &what, std::string const &parser_name)
Report a parse error (via FormatParseError) to the log, for use in a Spirit on_error handler.
Definition qi_files.hpp:199
std::string FormatParseError(std::string::const_iterator begin, std::string::const_iterator end, std::string::const_iterator err_pos, boost::spirit::info const &what, std::string const &parser_name)
Format a human-readable parse-error message (line, column, expected, and found text).
Definition qi_files.hpp:172
void StripUTF8BOM(std::string &s)
Strip a leading UTF-8 byte-order mark (EF BB BF) from s in place, if present.
Definition qi_files.hpp:74
void StripClassicComments(std::string &s)
Remove Bertini 1 comments from s in place: everything from a % to the end of its line.
Definition qi_files.hpp:91
void StripClassicFileWrappers(std::string &s)
Unwrap a Bertini 1 classic input FILE down to the declarations the grammar reads.
Definition qi_files.hpp:125
Definition algorithm_builder.hpp:36
UTF-8-aware identifier building blocks for the classic (Bertini 1) Qi grammar.