ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
cadical_parse.cpp
Go to the documentation of this file.
1#include "global.h"
2
3#include "internal.hpp"
4
6
7/*------------------------------------------------------------------------*/
8
9namespace CaDiCaL {
10
11/*------------------------------------------------------------------------*/
12
13// Parse error.
14
15#define PER(...) \
16 do { \
17 internal->error_message.init ( \
18 "%s:%" PRIu64 ": parse error: ", file->name (), \
19 (uint64_t) file->lineno ()); \
20 return internal->error_message.append (__VA_ARGS__); \
21 } while (0)
22
23/*------------------------------------------------------------------------*/
24
25// Parsing utilities.
26
27inline int Parser::parse_char () { return file->get (); }
28
29// Return an non zero error string if a parse error occurred.
30
31inline const char *Parser::parse_string (const char *str, char prev) {
32 for (const char *p = str; *p; p++)
33 if (parse_char () == *p)
34 prev = *p;
35 else if (*p == ' ')
36 PER ("expected space after '%c'", prev);
37 else
38 PER ("expected '%c' after '%c'", *p, prev);
39 return 0;
40}
41
42inline const char *Parser::parse_positive_int (int &ch, int &res,
43 const char *name) {
44 CADICAL_assert (isdigit (ch));
45 res = ch - '0';
46 while (isdigit (ch = parse_char ())) {
47 int digit = ch - '0';
48 if (INT_MAX / 10 < res || INT_MAX - digit < 10 * res)
49 PER ("too large '%s' in header", name);
50 res = 10 * res + digit;
51 }
52 return 0;
53}
54
55static const char *cube_token = "unexpected 'a' in CNF";
56
57inline const char *Parser::parse_lit (int &ch, int &lit, int &vars,
58 int strict) {
59 if (ch == 'a')
60 return cube_token;
61 int sign = 0;
62 if (ch == '-') {
63 if (!isdigit (ch = parse_char ()))
64 PER ("expected digit after '-'");
65 sign = -1;
66 } else if (!isdigit (ch))
67 PER ("expected digit or '-'");
68 else
69 sign = 1;
70 lit = ch - '0';
71 while (isdigit (ch = parse_char ())) {
72 int digit = ch - '0';
73 if (INT_MAX / 10 < lit || INT_MAX - digit < 10 * lit)
74 PER ("literal too large");
75 lit = 10 * lit + digit;
76 }
77 if (ch == '\r')
78 ch = parse_char ();
79 if (ch != 'c' && ch != ' ' && ch != '\t' && ch != '\n' && ch != EOF)
80 PER ("expected white space after '%d'", sign * lit);
81 if (lit > vars) {
82 if (strict != FORCED)
83 PER ("literal %d exceeds maximum variable %d", sign * lit, vars);
84 else
85 vars = lit;
86 }
87 lit *= sign;
88 return 0;
89}
90
91/*------------------------------------------------------------------------*/
92
93// Parsing CNF in DIMACS format.
94
95const char *Parser::parse_dimacs_non_profiled (int &vars, int strict) {
96
97#ifndef CADICAL_QUIET
98 double start = internal->time ();
99#endif
100
101 bool found_inccnf_header = false;
102 int ch, clauses = 0;
103 vars = 0;
104
105 // First read comments before header with possibly embedded options.
106 //
107 for (;;) {
108 ch = parse_char ();
109 if (strict != STRICT)
110 if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r')
111 continue;
112 if (ch != 'c')
113 break;
114 string buf;
115 while ((ch = parse_char ()) != '\n')
116 if (ch == EOF)
117 PER ("unexpected end-of-file in header comment");
118 else if (ch != '\r')
119 buf.push_back (ch);
120 const char *o;
121 for (o = buf.c_str (); *o && *o != '-'; o++)
122 ;
123 if (!*o)
124 continue;
125 PHASE ("parse-dimacs", "found option '%s'", o);
126 if (*o)
127 solver->set_long_option (o);
128 }
129
130 if (ch != 'p')
131 PER ("expected 'c' or 'p'");
132
133 ch = parse_char ();
134 if (strict == STRICT) {
135 if (ch != ' ')
136 PER ("expected space after 'p'");
137 ch = parse_char ();
138 } else if (ch != ' ' && ch != '\t')
139 PER ("expected white space after 'p'");
140 else {
141 do
142 ch = parse_char ();
143 while (ch == ' ' || ch == '\t');
144 }
145
146 // Now read 'p cnf <var> <clauses>' header of DIMACS file
147 // or 'p inccnf' of incremental 'INCCNF' file.
148 //
149 if (ch == 'c') {
150 CADICAL_assert (!found_inccnf_header);
151 if (strict == STRICT) {
152 const char *err = parse_string ("nf ", 'c');
153 if (err)
154 return err;
155 ch = parse_char ();
156 if (!isdigit (ch))
157 PER ("expected digit after 'p cnf '");
158 err = parse_positive_int (ch, vars, "<max-var>");
159 if (err)
160 return err;
161 if (ch != ' ')
162 PER ("expected ' ' after 'p cnf %d'", vars);
163 if (!isdigit (ch = parse_char ()))
164 PER ("expected digit after 'p cnf %d '", vars);
165 err = parse_positive_int (ch, clauses, "<num-clauses>");
166 if (err)
167 return err;
168 if (ch != '\n')
169 PER ("expected new-line after 'p cnf %d %d'", vars, clauses);
170 } else {
171 if (parse_char () != 'n')
172 PER ("expected 'n' after 'p c'");
173 if (parse_char () != 'f')
174 PER ("expected 'f' after 'p cn'");
175 ch = parse_char ();
176 if (!isspace (ch))
177 PER ("expected space after 'p cnf'");
178 do
179 ch = parse_char ();
180 while (isspace (ch));
181 if (!isdigit (ch))
182 PER ("expected digit after 'p cnf '");
183 const char *err = parse_positive_int (ch, vars, "<max-var>");
184 if (err)
185 return err;
186 if (!isspace (ch))
187 PER ("expected space after 'p cnf %d'", vars);
188 do
189 ch = parse_char ();
190 while (isspace (ch));
191 if (!isdigit (ch))
192 PER ("expected digit after 'p cnf %d '", vars);
193 err = parse_positive_int (ch, clauses, "<num-clauses>");
194 if (err)
195 return err;
196 while (ch != '\n') {
197 if (ch != '\r' && !isspace (ch))
198 PER ("expected new-line after 'p cnf %d %d'", vars, clauses);
199 ch = parse_char ();
200 }
201 }
202
203 MSG ("found %s'p cnf %d %d'%s header", tout.green_code (), vars,
204 clauses, tout.normal_code ());
205
206 if (strict != FORCED)
207 solver->reserve (vars);
208 internal->reserve_ids (clauses);
209 } else if (!parse_inccnf_too)
210 PER ("expected 'c' after 'p '");
211 else if (ch == 'i') {
212 found_inccnf_header = true;
213 const char *err = parse_string ("nccnf", 'i');
214 if (err)
215 return err;
216 ch = parse_char ();
217 if (strict == STRICT) {
218 if (ch != '\n')
219 PER ("expected new-line after 'p inccnf'");
220 } else {
221 while (ch != '\n') {
222 if (ch != '\r' && !isspace (ch))
223 PER ("expected new-line after 'p inccnf'");
224 ch = parse_char ();
225 }
226 }
227
228 MSG ("found %s'p inccnf'%s header", tout.green_code (),
229 tout.normal_code ());
230
231 strict = FORCED;
232 } else
233 PER ("expected 'c' or 'i' after 'p '");
234
235 if (parse_inccnf_too)
236 *parse_inccnf_too = false;
237
238 // Now read body of DIMACS part.
239 //
240 int lit = 0, parsed = 0;
241 while ((ch = parse_char ()) != EOF) {
242 if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r')
243 continue;
244 if (ch == 'c') {
245 while ((ch = parse_char ()) != '\n' && ch != EOF)
246 ;
247 if (ch == EOF)
248 break;
249 continue;
250 }
251 if (ch == 'a' && found_inccnf_header)
252 break;
253 const char *err = parse_lit (ch, lit, vars, strict);
254 if (err)
255 return err;
256 if (ch == 'c') {
257 while ((ch = parse_char ()) != '\n')
258 if (ch == EOF)
259 PER ("unexpected end-of-file in comment");
260 }
261 solver->add (lit);
262 if (!found_inccnf_header && !lit && parsed++ >= clauses &&
263 strict != FORCED)
264 PER ("too many clauses");
265 }
266
267 if (lit)
268 PER ("last clause without terminating '0'");
269
270 if (!found_inccnf_header && parsed < clauses && strict != FORCED)
271 PER ("clause missing");
272
273#ifndef CADICAL_QUIET
274 double end = internal->time ();
275 MSG ("parsed %d clauses in %.2f seconds %s time", parsed, end - start,
276 internal->opts.realtime ? "real" : "process");
277#endif
278
279#ifndef CADICAL_QUIET
280 start = end;
281 size_t num_cubes = 0;
282#endif
283 if (ch == 'a') {
284 CADICAL_assert (parse_inccnf_too);
285 CADICAL_assert (found_inccnf_header);
286 if (!*parse_inccnf_too)
287 *parse_inccnf_too = true;
288 for (;;) {
289 ch = parse_char ();
290 if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r')
291 continue;
292 if (ch == 'c') {
293 while ((ch = parse_char ()) != '\n' && ch != EOF)
294 ;
295 if (ch == EOF)
296 break;
297 continue;
298 }
299 const char *err = parse_lit (ch, lit, vars, strict);
300 if (err == cube_token)
301 PER ("two 'a' in a row");
302 else if (err)
303 return err;
304 if (ch == 'c') {
305 while ((ch = parse_char ()) != '\n')
306 if (ch == EOF)
307 PER ("unexpected end-of-file in comment");
308 }
309 if (cubes)
310 cubes->push_back (lit);
311 if (!lit) {
312#ifndef CADICAL_QUIET
313 num_cubes++;
314#endif
315 for (;;) {
316 ch = parse_char ();
317 if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r')
318 continue;
319 if (ch == 'c') {
320 while ((ch = parse_char ()) != '\n' && ch != EOF)
321 ;
322 if (ch == EOF)
323 break;
324 }
325 if (ch == EOF)
326 break;
327 if (ch != 'a')
328 PER ("expected 'a' or end-of-file after zero");
329 lit = INT_MIN;
330 break;
331 }
332 if (ch == EOF)
333 break;
334 }
335 }
336 if (lit)
337 PER ("last cube without terminating '0'");
338 }
339#ifndef CADICAL_QUIET
340 if (found_inccnf_header) {
341 double end = internal->time ();
342 MSG ("parsed %zd cubes in %.2f seconds %s time", num_cubes, end - start,
343 internal->opts.realtime ? "real" : "process");
344 }
345#endif
346
347 return 0;
348}
349
350/*------------------------------------------------------------------------*/
351
352// Parsing solution in competition output format.
353
354const char *Parser::parse_solution_non_profiled () {
355 external->solution = new signed char[external->max_var + 1u];
356 external->solution_size = external->max_var;
357 clear_n (external->solution, external->max_var + 1u);
358 int ch;
359 for (;;) {
360 ch = parse_char ();
361 if (ch == EOF)
362 PER ("missing 's' line");
363 else if (ch == 'c') {
364 while ((ch = parse_char ()) != '\n')
365 if (ch == EOF)
366 PER ("unexpected end-of-file in comment");
367 } else if (ch == 's')
368 break;
369 else
370 PER ("expected 'c' or 's'");
371 }
372 const char *err = parse_string (" SATISFIABLE", 's');
373 if (err)
374 return err;
375 if ((ch = parse_char ()) == '\r')
376 ch = parse_char ();
377 if (ch != '\n')
378 PER ("expected new-line after 's SATISFIABLE'");
379#ifndef CADICAL_QUIET
380 int count = 0;
381#endif
382 for (;;) {
383 ch = parse_char ();
384 if (ch != 'v')
385 PER ("expected 'v' at start-of-line");
386 if ((ch = parse_char ()) != ' ')
387 PER ("expected ' ' after 'v'");
388 int lit = 0;
389 ch = parse_char ();
390 do {
391 if (ch == ' ' || ch == '\t') {
392 ch = parse_char ();
393 continue;
394 }
395 err = parse_lit (ch, lit, external->max_var, false);
396 if (err)
397 return err;
398 if (ch == 'c')
399 PER ("unexpected comment");
400 if (!lit)
401 break;
402 if (external->solution[abs (lit)])
403 PER ("variable %d occurs twice", abs (lit));
404 LOG ("solution %d", lit);
405 external->solution[abs (lit)] = sign (lit);
406#ifndef CADICAL_QUIET
407 count++;
408#endif
409 if (ch == '\r')
410 ch = parse_char ();
411 } while (ch != '\n');
412 if (!lit)
413 break;
414 }
415 MSG ("parsed %d values %.2f%%", count,
416 percent (count, external->max_var));
417 return 0;
418}
419
420/*------------------------------------------------------------------------*/
421
422// Wrappers to profile parsing and at the same time use the convenient
423// implicit 'return' in PER in the non-profiled versions.
424
425const char *Parser::parse_dimacs (int &vars, int strict) {
426 CADICAL_assert (strict == FORCED || strict == RELAXED || strict == STRICT);
427 START (parse);
428 const char *err = parse_dimacs_non_profiled (vars, strict);
429 STOP (parse);
430 return err;
431}
432
434 START (parse);
435 const char *err = parse_solution_non_profiled ();
436 STOP (parse);
437 return err;
438}
439
440} // namespace CaDiCaL
441
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
#define CADICAL_assert(ignore)
Definition global.h:14
#define LOG(...)
#define PER(...)
const char * parse_dimacs(int &vars, int strict)
const char * parse_solution()
const char * normal_code()
Definition terminal.hpp:80
const char * green_code()
Definition terminal.hpp:76
Cube * p
Definition exorList.c:222
#define PHASE(...)
Definition message.hpp:52
#define MSG(...)
Definition message.hpp:49
char * name
Definition main.h:24
int sign(int lit)
Definition util.hpp:22
void clear_n(T *base, size_t n)
Definition util.hpp:149
Terminal tout(stdout)
Definition terminal.hpp:97
double percent(double a, double b)
Definition util.hpp:21
#define STOP(P)
Definition profile.hpp:158
#define START(P)
Definition profile.hpp:150
int lit
Definition satVec.h:130
Definition file.h:23