cgv
Loading...
Searching...
No Matches
command_token.cxx
1#include "command_token.h"
2#include <cgv/utils/scan.h>
4#include <cgv/utils/tokenizer.h>
5
6using namespace cgv::utils;
7
8namespace cgv {
9 namespace ppp {
10
11 std::string command_token::last_error;
12 token command_token::last_error_token;
13
15 {
16 CommandType ct;
17 const char* word;
18 unsigned length;
19 unsigned skip_length;
20 unsigned min_nr_expressions;
21 unsigned nr_expressions;
22 bool block_follows;
23 bool remove_empty_before;
24 bool parse_expressions;
25 const char* open_parentheses;
26 const char* close_parentheses;
27 };
28
29 const command_info& get_command_info(CommandType ct)
30 {
31 static const command_info infos[] = {
32 { CT_TEXT, "text", 4, 4, 1, 1, false, true, true, "(", ")" },
33 { CT_DEFINE, "define", 6, 6, 1, 1, false, true, true, "(", ")" },
34 { CT_SKIP, "skip", 4, 4, 1, 1, false, true, true, "(", ")" },
35 { CT_READ, "read", 4, 4, 3, 3, false, true, true, "(", ")" },
36 { CT_WRITE, "write", 5, 5, 3, 3, false, true, true, "(", ")" },
37 { CT_RAND, "rand", 4, 4, 3, 4, false, true, true, "(", ")" },
38 { CT_NAMESPACE, "namespace", 9, 9, 1, 1, true, true, true, "(", ")" },
39 { CT_FOR, "for", 3, 3, 3, 3, true, true, true, "(", ")" },
40 { CT_IF, "if", 2, 2, 1, 1, true, true, true, "(", ")" },
41 { CT_ELIF, "elif", 4, 4, 1, 1, true, true, true, "(", ")" },
42 { CT_ELSE, "else", 4, 4, 0, 0, true, true, true, "", "" },
43 { CT_EVAL, "(", 1, 0, 1, 1, false, false, true, "(", ")" },
44 { CT_STRING, "\"", 1, 0, 1, 1, false, false, true, "\"", "\"" },
45 { CT_LIST, "[", 1, 0, 3, 3, false, false, true, "[", "]" },
46 { CT_BEGIN, "{", 1, 1, 0, 0, false, true, true, "", "" },
47 { CT_END, "}", 1, 1, 0, 0, false, true, true, "", "" },
48 { CT_INCLUDE, "include", 7, 7, 1, 1, false, true, false, "<\"(", ">\")" },
49 { CT_CINCLUDE, "#include", 8, 8, 1, 1, false, true, false, "<\"(", ">\")" },
50 { CT_EXCLUDE, "exclude", 7, 7, 1, 1, false, true, false, "<\"(", ">\")" },
51 { CT_INSERT, "insert", 6, 6, 1, 1, false, true, false, "<\"(", ">\")" },
52 { CT_REFLECT_NEXT_LINE, ">", 1, 1, 0, 0, false, false, false, "", "" },
53 { CT_REFLECT_PREV_LINE, "<", 1, 1, 0, 0, false, false, false, "", "" },
54 { CT_COUT, "cout", 4, 4, 1, 1, false, true, true, "(", ")" },
55 { CT_CIN, "cin", 3, 3, 1, 1, false, true, true, "(", ")" },
56 { CT_ERROR, "error", 5, 5, 2, 2, false, true, true, "(", ")" },
57 { CT_WARNING, "warning", 7, 7, 2, 2, false, true, true, "(", ")" },
58 { CT_SYSTEM, "system", 6, 6, 2, 2, false, true, true, "(", ")" },
59 { CT_DIR, "dir", 3, 3, 4, 4, false, true, true, "(", ")" },
60 { CT_FUNC, "func", 4, 4, 1, 2, true, true, true, "(", ")" },
61 { CT_EXIT, "exit", 4, 4, 1, 1, false, true, true, "(", ")" },
62 { CT_TRANSFORM, "transform", 9, 9, 2, 2, false, true, true, "(", ")" },
63 { CT_SCAN_INCLUDES, "scan_includes", 13, 13, 2, 2, false, true, true, "(", ")" },
64 };
65 return infos[ct];
66 }
67
68 const char* get_command_word(CommandType ct)
69 {
70 switch (ct) {
71 case CT_IMPLICIT_TEXT: return "text";
72 case CT_UNDEF: return "undef";
73 default: return get_command_info(ct).word;
74 }
75 }
76
77
78 CommandType determine_command_type(const std::string& s)
79 {
80 // analyze length of command
81 unsigned l = 0;
82 while (l < s.size() && (is_digit(s[l]) || is_letter(s[l]) || s[l] == '#' || s[l] == '_'))
83 ++l;
84 if (l == 0)
85 l = 1;
86
87 for (CommandType ct = (CommandType)0; ct < CT_UNDEF; ct = CommandType(ct + 1)) {
88 const command_info& ci = get_command_info(ct);
89 if (l == ci.length && s.substr(0, ci.length) == ci.word)
90 return ct;
91 }
92 return CT_UNDEF;
93 }
94
96 : ct(CT_UNDEF), parenthesis_index(0), block_end(0)
97 {
98 }
101 : token(t), ct(CT_IMPLICIT_TEXT), parenthesis_index(0), block_end(0)
102 {
103 }
104
107 {
108 return get_command_info(ct).skip_length;
109 }
110
113 {
114 return get_command_info(ct).nr_expressions;
115 }
116
119 {
120 return get_command_info(ct).min_nr_expressions;
121 }
122
128
129
131 const char* command_token::get_keyword() const
132 {
133 return get_command_info(ct).word;
134 }
135
138 {
139 if (ct != CT_IMPLICIT_TEXT)
140 return false;
141 if (empty())
142 return true;
143
144 if (skip_spaces(begin, end) != end)
145 return false;
146
147 unsigned int nr_lines = 0;
148 for (const char* p = begin; p < end; ++p)
149 if (*p == '\n')
150 if (++nr_lines > 1)
151 break;
152 if (nr_lines < 2)
153 return true;
154 return false;
155 }
156
159 {
160 if (ct == CT_IMPLICIT_TEXT || ct == CT_UNDEF)
161 return false;
162 return get_command_info(ct).block_follows;
163 }
164
167 {
168 if (ct == CT_IMPLICIT_TEXT || ct == CT_UNDEF)
169 return false;
170 return get_command_info(ct).remove_empty_before;
171 }
172
173
176 {
177 return get_command_info(ct).open_parentheses[parenthesis_index];
178 }
179
182 {
183 return get_command_info(ct).close_parentheses[parenthesis_index];
184 }
185
188 {
189 std::string s = to_string(t);
190 ct = determine_command_type(s);
191 if (ct == CT_UNDEF) {
192 last_error = "could not determine command";
193 last_error_token = t;
194 return false;
195 }
196 begin = t.begin;
197 t.begin += get_skip_length();
198 end = t.begin;
199 unsigned ne = get_nr_expressions();
200 unsigned mne = get_min_nr_expressions();
201 if (ne == 0)
202 return true;
203
204 const std::string& open_ps = get_command_info(ct).open_parentheses;
205 const std::string& close_ps = get_command_info(ct).close_parentheses;
206
207 token exp_tok;
208 if (tokenizer(t).set_skip("'\"", "'\"").balanced_bite(exp_tok, open_ps, close_ps)) {
209 if (!is_element(*exp_tok.begin, open_ps)) {
210 last_error = "enclosing parenthesis not valid";
211 last_error_token = *this;
212 return false;
213 }
214 t.begin = exp_tok.end;
215 parenthesis_index = (int)open_ps.find_first_of(*exp_tok.begin);
216 ++exp_tok.begin;
217 --exp_tok.end;
218 std::vector<token> expr_tokens;
219 bite_all(tokenizer(exp_tok).set_skip("'\"", "'\"").set_ws(";"), expr_tokens);
220 if (expr_tokens.size() > ne || expr_tokens.size() < mne) {
221 last_error = "found " + to_string(expr_tokens.size()) + " expressions, but " + get_keyword() + " allows ";
222 if (ne == mne)
223 last_error += "only " + to_string(ne) + " expressions";
224 else
225 last_error += "from " + to_string(mne) + " to " + to_string(ne) + " expressions";
226 last_error_token = *this;
227 return false;
228 }
229 if (get_command_info(ct).parse_expressions || (parenthesis_index == 2)) {
230 for (unsigned int i = 0; i < expr_tokens.size(); ++i) {
232 if (!ep.parse(expr_tokens[i])) {
233 last_error = "parse error in expression ";
234 last_error += to_string(i + 1);
235 last_error_token = expr_tokens[i];
236 return false;
237 }
238 bool allow_several_values = false;
239 if (ct == CT_FUNC && i == 1)
240 allow_several_values = true;
241 if (!ep.validate(allow_several_values)) {
242 last_error = "could not validate expression ";
243 last_error += to_string(i + 1) + " (";
244 last_error += ep.get_last_error() + ")";
245 if (ep.get_last_error_token().empty())
246 last_error_token = expr_tokens[i];
247 else
248 last_error_token = ep.get_last_error_token();
249 return false;
250 }
251 expressions.push_back(ep);
252 }
253 }
254 else {
255 begin = exp_tok.begin;
256 end = exp_tok.end;
257 }
258 return true;
259 }
260 last_error = "could not find parenthesis enclosing expressions";
261 last_error_token = t;
262 return false;
263 }
264
265 const std::string& command_token::get_last_error()
266 {
267 return last_error;
268 }
269 const token& command_token::get_last_error_token()
270 {
271 return last_error_token;
272 }
273
274 }
275}
bool validate(bool allow_several_values=false)
the tokenizer allows to split text into tokens in a convenient way.
Definition tokenizer.h:68
Helper functions to convert numeric types into strings using std streams.
CommandType
enumerate type for all command types supported in configuration files
Definition register.h:470
namespace that holds tools that dont fit any other namespace
bool is_digit(char c)
check if char is a digit
Definition scan.cxx:20
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
void bite_all(tokenizer &t, std::vector< token > &result)
bite all tokens into a token vector
Definition tokenizer.h:121
bool is_element(char c, const std::string &s)
check if char c arises in string s
Definition scan.cxx:291
const char * skip_spaces(const char *begin, const char *end)
return new start pointer by skipping spaces at begin
Definition scan.cxx:683
the cgv namespace
Definition print.h:11
Helper functions to process strings.
unsigned get_skip_length() const
get the number of characters to be skipped before expressions start
bool is_nr_expressions_fix() const
return whether the number of expressions that the command takes as argument is fix
char get_close_parenthesis() const
return the close parenthesis enclosing the expressions
bool remove_preceeding_empty_text_token() const
return whether empty text tokens before this command token should be deleted
char get_open_parenthesis() const
return the open parenthesis enclosing the expressions
unsigned get_nr_expressions() const
return the number of expressions that the command takes as argument
bool block_follows() const
return whether the command token must be followed by a block
const char * get_keyword() const
return the keyword describing the command
bool is_empty() const
check whether the token only contains white spaces
bool split_off_from(token &t)
splits a command token from the front of a given token
command_token()
constructs an undefined command token
unsigned int parenthesis_index
store index of parenthesis that enclosed the expressions
CommandType ct
store command type
std::vector< expression_processor > expressions
vector of parsed expressions
unsigned get_min_nr_expressions() const
return the minimum number of expressions that the command takes as argument
representation of a token in a text by two pointers begin and end, that point to the first character ...
Definition token.h:18
bool empty() const
return whether the token is empty
Definition token.h:56
const char * begin
pointers that define the range of characters
Definition token.h:20