Vcsn  2.4
Be Rational
daut.cc
Go to the documentation of this file.
1 #include <fstream>
2 #include <string>
3 
4 #include <boost/algorithm/string/predicate.hpp>
5 #include <boost/algorithm/string/trim.hpp>
6 
7 #include <lib/vcsn/algos/fwd.hh>
9 #include <vcsn/algos/read.hh>
10 #include <vcsn/dyn/algos.hh>
11 #include <vcsn/dyn/automaton.hh>
12 #include <vcsn/misc/stream.hh>
13 #include <vcsn/misc/symbol.hh>
14 #include <vcsn/misc/regex.hh>
15 
16 namespace vcsn
17 {
18  namespace dyn
19  {
20  namespace
21  {
22  using string_t = symbol;
23 
25  std::string read_context(std::string& line)
26  {
27  // A context definition possibly followed by comments.
28  static auto re = std::regex("^[ \t]*(?:vcsn_)?(?:context|ctx)[ \t]*="
29  "[ \t]*(\"?)(.*?)\\1[ \t]*(?://.*)?$");
30  // To handle escaped characters.
31  static auto sub = std::regex("\\\\\\\\");
32  std::smatch m;
33  if (std::regex_match(line, m, re))
34  {
35  std::string res = m[2];
36  if (m[1] == "\"")
37  res = std::regex_replace(res, sub, "\\");
38  return res;
39  }
40  else
41  return "";
42  }
43 
45  std::string read_quotes(std::istream& is)
46  {
47  std::string res;
48  int c;
49  while ((c = is.peek()) != EOF && c != '"')
50  res += get_char(is);
51  if (c != '"')
52  raise("invalid daut file: missing '\"' after '" + res + "'");
53  is.ignore(); // Eat the final '"'
54  return res;
55  }
56 
59  bool is_comment(std::istream& is, char c)
60  {
61  if (c == '/' && is.peek() == '/')
62  {
63  is.unget(); // Put back the first '/'
64  return true;
65  }
66  else
67  return c == '#';
68  }
69 
70 
72  std::string read_state(std::istream& is)
73  {
74  std::string res;
75  int c;
76  skip_space(is);
77  while ((c = is.get()) != EOF)
78  {
79  if (c == '\\')
80  {
81  if ((c = is.get()) != EOF)
82  res += c;
83  continue;
84  }
85  if (c == '"')
86  return read_quotes(is);
87  if (isspace(c) || is_comment(is, c))
88  break;
89  res += c;
90  }
91  boost::algorithm::trim_right(res);
92  return res;
93 
94  }
95 
97  std::string read_entry(std::istream& is)
98  {
99  std::string res;
100  int c;
101  skip_space(is);
102  while ((c = is.get()) != EOF)
103  {
104  if (isspace(c) && res.empty())
105  continue;
106  if (is_comment(is, c))
107  break;
108  res += c;
109  }
110  return res;
111  }
112 
113  vcsn::automaton_editor* make_editor(std::string ctx)
114  {
115  auto c = vcsn::dyn::make_context(ctx.empty() ? "lal_char, b" : ctx);
116  auto res = vcsn::dyn::make_automaton_editor(c);
117  res->set_separator(',');
118  res->add_pre(string_t{"$pre"});
119  res->add_post(string_t{"$post"});
120  return res;
121  }
122  }
123 
124  automaton
125  read_daut(std::istream& is)
126  {
127  auto first = true;
128  std::shared_ptr<vcsn::automaton_editor> edit = nullptr;
129 
130  // Line: Source [->] Dest [Entry]
131  std::string line;
132  while (is.good())
133  {
134  std::getline(is, line, '\n');
135  // Trim here to handle line full of blanks.
136  boost::algorithm::trim_right(line);
137  if (line.empty() || boost::starts_with(line, "//"))
138  continue;
139 
140  if (first)
141  {
142  auto ctx = read_context(line);
143  edit.reset(make_editor(ctx));
144  first = false;
145  if (!ctx.empty())
146  continue;
147  }
148 
149  std::istringstream ss{line};
150  auto s = string_t{read_state(ss)};
151  auto d = string_t{read_state(ss)};
152  if (d.get().empty()) // Declaring a state with no transitions
153  {
154  edit->add_state(s);
155  continue;
156  }
157  if (d == "->")
158  d = read_state(ss);
159  require(!d.get().empty(),
160  "invalid daut file: expected destination after: ", s);
161  auto entry = string_t{read_entry(ss)};
162  try
163  {
164  edit->add_entry(s == "$" ? string_t{"$pre"} : s,
165  d == "$" ? string_t{"$post"} : d, entry);
166  }
167  catch (const std::runtime_error& e)
168  {
169  raise(e, " while adding transitions: (", s, ", ", entry, ", ",
170  d, ')');
171  }
172  }
173 
174  if (!edit)
175  edit.reset(make_editor(""));
176  return edit->result();
177  }
178  }
179 }
Abstract Builder (the design pattern) for automata.
return res
Definition: multiply.hh:398
symbol string_t
Definition: parse.hh:66
void require(Bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:91
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:23
context make_context(const std::string &name)
Build a context from its name.
Definition: others.cc:97
Definition: a-star.hh:8
void skip_space(std::istream &is)
Ignore spaces.
Definition: stream.cc:163
automaton read_daut(std::istream &is)
Definition: daut.cc:125
char get_char(std::istream &i)
Read a single char, with possible -escape support.
Definition: stream.cc:37
automaton_editor * make_automaton_editor(const context &ctx)
Build an automatonset from its context.