mCRL2
Loading...
Searching...
No Matches
aterm_io_text.cpp
Go to the documentation of this file.
1// Author(s): Jan Friso Groote
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
9
11
12#include <fstream>
13
14namespace atermpp
15{
16
17// utility functions
18
19static void write_string_with_escape_symbols(const std::string& s, std::ostream& os)
20{
21 // Check whether the string starts with a - or a number, or contains the symbols
22 // \, ", (, ), [, ], comma, space, \t, \n or \r. If yes, the string will be
23 // surrounded by quotes, and the symbols \, ", \t, \n, \r
24 // will be preceded by an escape symbol.
25
26 char c = s[0];
27 bool contains_special_symbols = ((c =='-') || isdigit(c));
28
29 for(std::string::const_iterator i=s.begin(); !contains_special_symbols && i!=s.end(); ++i)
30 {
31 if (*i=='\\' || *i=='"' || *i=='(' || *i==')' || *i=='[' || *i==']' || *i==',' || *i==' ' || *i=='\n' || *i=='\t' || *i=='\r')
32 {
33 contains_special_symbols=true;
34 }
35 }
36
37 if (contains_special_symbols)
38 {
39 // This function symbol needs quotes.
40 os << "\"";
41 for(std::string::const_iterator i=s.begin(); i!=s.end(); ++i)
42 {
43 // We need to escape special characters.
44 switch (*i)
45 {
46 case '\\':
47 case '"':
48 os << "\\" << *i;
49 break;
50 case '\n':
51 os << "\\n";
52 break;
53 case '\t':
54 os << "\\t";
55 break;
56 case '\r':
57 os << "\\r";
58 break;
59 default:
60 os << *i;
61 break;
62 }
63 }
64 os << "\"";
65 }
66 else
67 {
68 os << s;
69 }
70}
71
72// Public functions
73
74text_aterm_ostream::text_aterm_ostream(std::ostream& os, bool newline)
75 : m_stream(os),
76 m_newline(newline)
77{}
78
80{
81 write_term_line(term);
82
83 if (m_newline)
84 {
85 m_stream << "\n";
86 }
87}
88
90 : m_stream(is)
91{
93}
94
96{
97 try
98 {
99 if (character != EOF)
100 {
101 term = parse_aterm(character);
102 }
103 }
104 catch (std::runtime_error& e)
105 {
106 throw std::runtime_error(e.what() + std::string("\n") + print_parse_error_position());
107 }
108
109 // Reset the parsing error buffers.
110 m_column = 0;
111 m_history.clear();
112
113 return;
114}
115
116// Private functions
117
119{
120 if (t.type_is_int())
121 {
122 // Write a single integer as is.
123 m_stream << atermpp::down_cast<aterm_int>(t).value();
124 }
125 else if (t.type_is_list())
126 {
127 // A list l0...ln is formatted as [l0, ..., ln].
128 m_stream << "[";
129 const aterm_list& list = down_cast<aterm_list>(t);
130 for (aterm_list::const_iterator it = list.begin(); it != list.end(); ++it)
131 {
132 if (it!=list.begin())
133 {
134 m_stream << ",";
135 }
136 write_term_line(*it);
137 }
138
139 m_stream << "]";
140 }
141 else
142 {
143 // An aterm f(t0, ..., tn) is written as f(t0, ..., tn)
144 assert(t.type_is_appl());
145
146 aterm appl = m_transformer(t);
147
149
150 if (appl.function().arity() > 0)
151 {
152 m_stream << "(";
153 write_term_line(appl[0]);
154 for (std::size_t i = 1; i < appl.function().arity(); i++)
155 {
156 m_stream << ",";
157 write_term_line(appl[i]);
158 }
159 m_stream << ")";
160 }
161 }
162}
163
165{
166 // Parse the term.
167 switch (character)
168 {
169 case '"':
170 {
171 std::string function_name = parse_quoted_string(character);
172 return parse_aterm_appl(function_name, character);
173 }
174 case '[':
175 {
176 return parse_aterm_list(character, '[', ']');
177 }
178 default:
179 {
180 if (isdigit(character) || character == '-')
181 {
183 }
184
187 }
188 }
189}
190
191aterm text_aterm_istream::parse_aterm_appl(const std::string& function_name, int& character)
192{
193 // Parse the arguments.
194 aterm_list arguments = parse_aterm_list(character, '(', ')');
195
196 // Wrap up this function application.
197 function_symbol symbol(function_name, arguments.size());
198 return m_transformer(aterm(symbol, arguments.begin(), arguments.end()));
199}
200
202{
203 std::array<char, 32> number;
204 auto it = number.begin();
205
206 if (character == '-')
207 {
208 *it = static_cast<char>(character);
209 ++it;
210 character = next_char(true, true);
211 }
212
213 while (isdigit(character) && it != number.end())
214 {
215 *it = static_cast<char>(character);
216 ++it;
218 }
219
220 *it = '\0';
221 return aterm_int(static_cast<std::size_t>(atol(number.data())));
222}
223
224aterm_list text_aterm_istream::parse_aterm_list(int& character, char begin, char end)
225{
226 aterm_list list;
227
228 // A list is [t0, ..., tn] or surrounded by ().
229 if (character == begin)
230 {
231 character = next_char(true, true);
232 if (character != end)
233 {
234 list.push_front(parse_aterm(character));
235
236 while (character == ',')
237 {
238 character = next_char(true, true);
239 list.push_front(parse_aterm(character));
240 }
241
242 if (character != end)
243 {
244 throw std::runtime_error(std::string("Missing ") + end + " while parsing a list term");
245 }
246 }
247
248 character = next_char(true);
249 }
250
251 return reverse(list);
252}
253
254
256{
257 std::stringstream s;
258 s << "Error occurred at line " << m_line << ", col " << m_column << " near: ";
259 for(const auto& element : m_history)
260 {
261 s << element;
262 }
263 return s.str();
264}
265
266int text_aterm_istream::next_char(bool skip_whitespace, bool required)
267{
268 character = EOF;
269
270 do
271 {
272 try
273 {
274 // In liblts_lts the exception bit is set, so we need to use exception to handle EOF.
275 character = m_stream.get();
276 }
277 catch (std::ios::failure&)
278 {
279 return EOF;
280 }
281
282 if (character != EOF)
283 {
284 if (character == '\n')
285 {
286 m_line++;
287 m_column = 0;
288 }
289 else
290 {
291 m_column++;
292 }
293
294 if (m_history.size() >= m_history_limit)
295 {
296 // If the history is full the first element must be removed.
297 m_history.erase(m_history.begin());
298 }
299
300 m_history.emplace_back(character);
301 }
302 else if (required)
303 {
304 throw std::runtime_error("Premature end of file while parsing.");
305 }
306 }
307 while (isspace(character) && skip_whitespace);
308
309 // The stream also returns a newline for the last symbol.
310 return character == '\n' ? EOF : character;
311}
312
314{
315 // We need a buffer for printing and parsing.
316 std::string string;
317
318 assert(character == '"');
319
320 // First obtain the first symbol after ".
322
323 while (character != '"')
324 {
325 switch (character)
326 {
327 case '\\':
328 character = next_char(false, true);
329 switch (character)
330 {
331 case 'n':
332 string += '\n';
333 break;
334 case 'r':
335 string += '\r';
336 break;
337 case 't':
338 string += '\t';
339 break;
340 default:
341 string += static_cast<char>(character);
342 break;
343 }
344 break;
345 default:
346 string += static_cast<char>(character);
347 break;
348 }
349 character = next_char(false, true);
350 }
351
352 character = next_char(true, false);
353 return string;
354}
355
357{
358 std::string string;
359
360 if (character != '(')
361 {
362 // First parse the identifier
363 while (character != '"' && character != '(' && character != ')' && character != ']'
364 && character != ']' && character != ',' && character != ' ' && character != '\n'
365 && character != '\t' && character != '\r' && character != EOF)
366 {
367 string += static_cast<char>(character);
368 character = next_char(false);
369 }
370 }
371
372 return string;
373}
374
375void write_term_to_text_stream(const aterm& term, std::ostream& os)
376{
377 text_aterm_ostream(os) << term;
378}
379
380aterm read_term_from_string(const std::string& s)
381{
382 std::stringstream ss(s);
383 aterm t;
385 return t;
386}
387
388void read_term_from_text_stream(std::istream& is, aterm& t)
389{
390 text_aterm_istream(is).get(t);
391}
392
393
394std::ostream& operator<<(std::ostream& os, const aterm& term)
395{
396 text_aterm_ostream(os) << term;
397 return os;
398}
399
400} // namespace atermpp
An integer term stores a single std::size_t value. It carries no arguments.
Definition aterm_int.h:26
aterm_transformer * m_transformer
Definition aterm_io.h:42
const_iterator end() const
Returns a const_iterator pointing past the last argument.
Definition aterm.h:172
const_iterator begin() const
Returns an iterator pointing to the first argument.
Definition aterm.h:165
const function_symbol & function() const
Returns the function symbol belonging to an aterm.
Definition aterm.h:144
std::size_t arity() const
Return the arity (number of arguments) of the function symbol (function_symbol).
const std::string & name() const
Return the name of the function_symbol.
Iterator for term_list.
A list of aterm objects.
Definition aterm_list.h:24
size_type size() const
Returns the size of the term_list.
Definition aterm_list.h:256
const_iterator end() const
Returns a const_iterator pointing to the end of the term_list.
Definition aterm_list.h:282
const_iterator begin() const
Returns a const_iterator pointing to the beginning of the term_list.
Definition aterm_list.h:275
Reads terms in textual format from an input stream.
std::size_t m_history_limit
Determines the maximum number of characters that are stored.
std::size_t m_column
The column of the current character.
std::deque< char > m_history
Stores the characters that have been read so-far.
std::string print_parse_error_position()
aterm_int parse_aterm_int(int &character)
Parses an std::size_t as an aterm_int.
aterm parse_aterm(int &character)
Parse a term from the input stream and return it.
text_aterm_istream(std::istream &os)
std::string parse_quoted_string(int &character)
Reads a quoted string from the stream.
aterm parse_aterm_appl(const std::string &function_name, int &character)
Parses an "f"(t0, ..., tn) application as an aterm.
int next_char(bool skip_whitespace=true, bool required=false)
aterm_list parse_aterm_list(int &character, char begin, char end)
Parses a list of arguments [...] as terms.
std::string parse_unquoted_string(int &character)
Reads an unquoted string from the stream.
void get(aterm &t) override
Reads an aterm from this stream.
int character
The last character that was read.
std::size_t m_line
The line number of the current character.
Writes terms in textual format to an output stream.
bool m_newline
Indicates that terms are separated by a newline.
void write_term_line(const aterm &term)
Writes a term in textual format on the same line.
void put(const aterm &term) override
Write the given term to the stream.
text_aterm_ostream(std::ostream &os, bool newline=false)
bool type_is_list() const noexcept
Dynamic check whether the term is an aterm_list.
Definition aterm_core.h:72
bool type_is_appl() const noexcept
Dynamic check whether the term is an aterm.
Definition aterm_core.h:55
bool type_is_int() const noexcept
Dynamic check whether the term is an aterm_int.
Definition aterm_core.h:63
const_iterator end() const
const_iterator begin() const
The main namespace for the aterm++ library.
Definition algorithm.h:21
std::ostream & operator<<(std::ostream &out, const atermpp::aterm &t)
Send the term in textual form to the ostream.
static void write_string_with_escape_symbols(const std::string &s, std::ostream &os)
term_list< Term > reverse(const term_list< Term > &l)
Returns the list with the elements in reversed order.
aterm read_term_from_string(const std::string &s)
Reads an aterm from a string. The string can be in either binary or text format.
void write_term_to_text_stream(const aterm &t, std::ostream &os)
Writes term t to a stream in textual format.
void read_term_from_text_stream(std::istream &is, aterm &t)
Reads a term from a stream which contains the term in textual format.