tudocomp
– The TU Dortmund Compression Framework
AlgorithmAST.hpp
Go to the documentation of this file.
1 #pragma once
2 
4 
5 #include <stdexcept>
6 
7 namespace tdc {
9  namespace ast {
10  class ParseError: public std::runtime_error {
11  public:
12  inline ParseError(const std::string& cause, size_t pos, std::string input):
13  std::runtime_error(cause
14  + ", found "
15  + input.substr(pos)) {}
16  };
17 
18  // A simple recursive parser
19  class Parser {
20  View m_text;
21  size_t m_cursor;
22 
23  inline void error(const std::string& cause) {
24  throw ParseError(cause, m_cursor, m_text);
25  }
26  inline void error_ident() {
27  error("Expected an identifier");
28  }
29 
30  typedef bool (*acceptor)(char c);
31 
32  template<char acc>
33  static inline bool accept_char(char c) {
34  return (c == acc);
35  }
36 
37  static inline bool accept_numeric(char c) {
38  //yes, very lenient
39  return (c == '-') || (c == '.') || (c >= '0' && c <= '9');
40  }
41 
42  static inline bool accept_non_numeric(char c) {
43  return !accept_numeric(c);
44  }
45  public:
46  inline Parser(View text): m_text(text), m_cursor(0) {}
47 
48  inline bool has_next();
49  inline Value parse_value(View already_parsed_ident = View(""));
50  inline Value parse_single_value(View already_parsed_ident = View(""));
51  inline Arg parse_arg();
52  inline View parse_ident();
53  inline void parse_whitespace();
54  inline bool parse_char(acceptor accept);
55  inline bool peek_char(acceptor accept);
56  inline std::string parse_string(
57  acceptor delim, const std::string& help, bool enclose = true);
58  inline bool parse_keyword(View keyword);
59  inline View expect_ident();
60  };
61 
62  inline bool Parser::has_next() {
63  return m_cursor < m_text.size();
64  }
65 
66  inline Value Parser::parse_single_value(View already_parsed_ident) {
67  parse_whitespace();
68 
69  if (already_parsed_ident.size() == 0) {
70  if (peek_char(accept_char<'"'>)) {
71  return Value(parse_string(accept_char<'"'>, "\""));
72  }
73  if (peek_char(accept_char<'\''>)) {
74  return Value(parse_string(accept_char<'\''>, "'"));
75  }
76  if (peek_char(accept_numeric)) {
77  return Value(parse_string(accept_non_numeric, "non-numeric", false));
78  }
79  }
80 
81  View value_name("");
82 
83  if (already_parsed_ident.size() > 0) {
84  value_name = already_parsed_ident;
85  } else {
86  value_name = expect_ident();
87  }
88 
89  if (value_name == "true"
90  || value_name == "false") {
91  return Value(value_name);
92  }
93 
94  std::vector<Arg> args;
95  bool first = true;
96  parse_whitespace();
97  if (parse_char(accept_char<'('>)) {
98  while(true) {
99  parse_whitespace();
100  if (parse_char(accept_char<')'>)) {
101  break;
102  } else if (first || parse_char(accept_char<','>)) {
103  if (parse_char(accept_char<')'>)) {
104  // allow trailling commas
105  break;
106  }
107  first = false;
108  args.push_back(parse_arg());
109  } else {
110  error("Expected ) or ,");
111  }
112  }
113  }
114 
115  return Value(value_name, std::move(args));
116 
117  }
118 
119  inline Value Parser::parse_value(View already_parsed_ident) {
120  Value val1 = parse_single_value(already_parsed_ident);
121  while (parse_char(accept_char<':'>)) {
122  Value val2 = parse_single_value();
123  val1 = Value("chain", {
124  Arg(std::move(val1)),
125  Arg(std::move(val2)),
126  });
127  }
128  return val1;
129  }
130 
131  inline Arg Parser::parse_arg() {
132  //return Arg(Value("test"));
133 
134  auto ident = parse_ident();
135 
136  bool has_type = false;
137  bool is_static = false;
138  View type_ident("");
139 
140  bool has_keyword = false;
141  View keyword_ident("");
142 
143  if (ident.size() > 0 && parse_char(accept_char<'='>)) {
144  keyword_ident = ident;
145  ident.clear();
146  has_keyword = true;
147  }
148 
149  auto value = parse_value(ident);
150 
151  if (has_keyword && has_type) {
152  return Arg(keyword_ident,
153  is_static,
154  type_ident,
155  std::move(value));
156  } else if (!has_keyword && has_type) {
157  return Arg(is_static,
158  type_ident,
159  std::move(value));
160  } else if (has_keyword && !has_type) {
161  return Arg(keyword_ident,
162  std::move(value));
163  } else {
164  return Arg(std::move(value));
165  }
166  }
167  inline View Parser::parse_ident() {
168  parse_whitespace();
169  size_t ident_start = m_cursor;
170  if (m_cursor < m_text.size()) {
171  auto c = m_text[m_cursor];
172  if (c == '_'
173  || (c >= 'a' && c <= 'z')
174  || (c >= 'A' && c <= 'Z')
175  ) {
176  // char is valid in an IDENT
177  m_cursor++;
178  } else {
179  return m_text.slice(ident_start, m_cursor);
180  }
181  }
182  for (; m_cursor < m_text.size(); m_cursor++) {
183  auto c = m_text[m_cursor];
184  if (c == '_'
185  || (c >= 'a' && c <= 'z')
186  || (c >= 'A' && c <= 'Z')
187  || (c >= '0' && c <= '9')
188  ) {
189  // char is valid in an IDENT
190  } else {
191  break;
192  }
193  }
194  return m_text.slice(ident_start, m_cursor);
195  }
196  inline void Parser::parse_whitespace() {
197  if (!has_next()) {
198  return;
199  }
200  while (m_text[m_cursor] == ' '
201  || m_text[m_cursor] == '\n'
202  || m_text[m_cursor] == '\r'
203  || m_text[m_cursor] == '\t')
204  {
205  m_cursor++;
206  }
207  }
208  inline bool Parser::parse_char(acceptor accept) {
209  bool r = peek_char(accept);
210  if (r) {
211  m_cursor++;
212  }
213  return r;
214  }
215  inline bool Parser::peek_char(acceptor accept) {
216  if (!has_next()) {
217  return false;
218  }
219  parse_whitespace();
220  return accept(m_text[m_cursor]);
221  }
222  inline std::string Parser::parse_string(
223  acceptor delim, const std::string& help, bool enclose) {
224 
225  size_t start;
226  size_t end;
227  if (!enclose || parse_char(delim)) {
228  start = m_cursor;
229  end = start - 1;
230  while(has_next()) {
231  if(enclose) {
232  if (parse_char(delim)) {
233  end = m_cursor - 1;
234  break;
235  }
236  } else {
237  if(peek_char(delim)) {
238  end = m_cursor;
239  break;
240  }
241  }
242  m_cursor++;
243  }
244  if (end >= start) {
245  return m_text.slice(start, end);
246  }
247  }
248  error(std::string("Expected ") + help);
249  return "";
250  }
251  inline bool Parser::parse_keyword(View keyword) {
252  parse_whitespace();
253  if (m_text.slice(m_cursor).starts_with(keyword)) {
254  m_cursor += keyword.size();
255  return true;
256  }
257  return false;
258  }
259  inline View Parser::expect_ident() {
260  View ident = parse_ident();
261  if (ident.size() == 0) {
262  error_ident();
263  }
264  return ident;
265  }
266  }
268 }
Contains the text compression and encoding framework.
Definition: namespaces.hpp:11
len_compact_t pos
Definition: LZSSFactors.hpp:38
ByteView View
Definition: View.hpp:25