2022-08-30 15:42:35 +08:00

407 lines
9.1 KiB
C

#include "internal.h"
#include "parse.h"
#include "print.h"
#include "profile.h"
#include "resize.h"
#include <ctype.h>
#include <inttypes.h>
static int
next (file * file, uint64_t * lineno_ptr)
{
int ch = kissat_getc (file);
if (ch == '\n')
*lineno_ptr += 1;
return ch;
}
#define NEXT() \
next (file, lineno_ptr)
static const char *
nonl (int ch, const char *str, uint64_t * lineno_ptr)
{
if (ch == '\n')
{
assert (*lineno_ptr > 1);
*lineno_ptr -= 1;
}
return str;
}
#define TRY_RELAXED_PARSING "(try '--relaxed' parsing)"
static const char *
parse_dimacs (kissat * solver, strictness strict,
file * file, uint64_t * lineno_ptr, int *max_var_ptr)
{
*lineno_ptr = 1;
bool first = true;
int ch;
for (;;)
{
ch = NEXT ();
if (ch == 'p')
break;
else if (ch == EOF)
{
if (first)
return "empty file";
else
return "end-of-file before header";
}
first = false;
if (ch == '\r')
{
ch = NEXT ();
if (ch != '\n')
return "expected new-line after carriage-return";
if (strict == PEDANTIC_PARSING)
return nonl (ch, "unexpected empty line", lineno_ptr);
}
else if (ch == '\n')
{
if (strict == PEDANTIC_PARSING)
return nonl (ch, "unexpected empty line", lineno_ptr);
}
else if (ch == 'c')
{
START:
ch = NEXT ();
if (ch == '\n')
continue;
else if (ch == '\r')
{
ch = NEXT ();
if (ch != '\n')
return "expected new-line after carriage-return";
continue;
}
else if (ch == EOF)
return "end-of-file in header comment";
else if (ch == ' ' || ch == '\t')
goto START;
#if !defined(NOPTIONS) && !defined(NEMBEDDED)
else if (ch == '-' && GET_OPTION (embedded))
{
ch = NEXT ();
if (ch != '-')
goto COMPLETE;
char name[32];
unsigned pos = 0;
while ('a' <= (ch = NEXT ()) && ch <= 'z')
{
assert (pos < sizeof name);
name[pos++] = ch;
if (pos == sizeof name)
goto COMPLETE;
}
if (ch == '\r')
{
ch = NEXT ();
if (ch != '\n')
return "expected new-line after carriage-return";
}
if (ch == '\n')
continue;
if (ch != '=')
goto COMPLETE;
assert (pos < sizeof name);
name[pos++] = 0;
pos = 0;
ch = NEXT ();
int sign;
if (ch == '-')
{
ch = NEXT ();
sign = -1;
}
else
sign = 1;
if (!isdigit (ch))
goto COMPLETE;
int arg = ch - '0';
while (isdigit (ch = NEXT ()))
{
if (INT_MAX / 10 < arg)
goto COMPLETE;
arg *= 10;
int digit = ch - '0';
if (INT_MAX - digit < arg)
goto COMPLETE;
arg += digit;
}
while (ch == ' ' || ch == '\t')
ch = NEXT ();
if (ch == '\r')
{
ch = NEXT ();
if (ch != '\n')
return "expected new-line after carriage-return";
}
if (ch != '\n')
goto COMPLETE;
arg *= sign;
const opt *opt = kissat_options_has (name);
if (opt)
{
(void) kissat_options_set_opt (&solver->options, opt, arg);
kissat_verbose (solver,
"parsed embedded option '--%s=%d'",
name, arg);
}
else
kissat_warning (solver,
"invalid embedded option '--%s=%d'",
name, arg);
continue;
}
else
#endif
{
while ((ch = NEXT ()) != '\n')
#if !defined(NOPTIONS) && !defined(NEMBEDDED)
COMPLETE:
#endif
if (ch == EOF)
return "end-of-file in header comment";
else if (ch == '\r')
{
ch = NEXT ();
if (ch != '\n')
return "expected new-line after carriage-return";
break;
}
}
}
else
return "expected 'c' or 'p' at start of line";
}
assert (ch == 'p');
ch = NEXT ();
if (ch != ' ')
return nonl (ch, "expected space after 'p'", lineno_ptr);
ch = NEXT ();
if (strict != PEDANTIC_PARSING)
{
while (ch == ' ' || ch == '\t')
ch = NEXT ();
}
if (ch != 'c')
return nonl (ch, "expected 'c' after 'p '", lineno_ptr);
ch = NEXT ();
if (ch != 'n')
return nonl (ch, "expected 'n' after 'p c'", lineno_ptr);
ch = NEXT ();
if (ch != 'f')
return nonl (ch, "expected 'n' after 'p cn'", lineno_ptr);
ch = NEXT ();
if (ch != ' ')
return nonl (ch, "expected space after 'p cnf'", lineno_ptr);
ch = NEXT ();
if (strict != PEDANTIC_PARSING)
{
while (ch == ' ' || ch == '\t')
ch = NEXT ();
}
if (!isdigit (ch))
return nonl (ch, "expected digit after 'p cnf '", lineno_ptr);
int variables = ch - '0';
while (isdigit (ch = NEXT ()))
{
if (EXTERNAL_MAX_VAR / 10 < variables)
return "maximum variable too large";
variables *= 10;
const int digit = ch - '0';
if (EXTERNAL_MAX_VAR - digit < variables)
return "maximum variable too large";
variables += digit;
}
if (ch == EOF)
return "unexpected end-of-file while parsing maximum variable";
if (ch == '\r')
{
ch = NEXT ();
if (ch != '\n')
return "expected new-line after carriage-return";
}
if (ch == '\n')
return nonl (ch, "unexpected new-line after maximum variable",
lineno_ptr);
if (ch != ' ')
return "expected space after maximum variable";
ch = NEXT ();
if (strict != PEDANTIC_PARSING)
{
while (ch == ' ' || ch == '\t')
ch = NEXT ();
}
if (!isdigit (ch))
return "expected number of clauses after maximum variable";
uint64_t clauses = ch - '0';
while (isdigit (ch = NEXT ()))
{
if (UINT64_MAX / 10 < clauses)
return "number of clauses too large";
clauses *= 10;
const int digit = ch - '0';
if (UINT64_MAX - digit < clauses)
return "number of clauses too large";
clauses += digit;
}
if (ch == EOF)
return "unexpected end-of-file while parsing number of clauses";
if (strict != PEDANTIC_PARSING)
{
while (ch == ' ' || ch == '\t')
ch = NEXT ();
}
if (ch == '\r')
{
ch = NEXT ();
if (ch != '\n')
return "expected new-line after carriage-return";
}
if (ch == EOF)
return "unexpected end-of-file after parsing number of clauses";
if (ch != '\n')
return "expected new-line after parsing number of clauses";
// kissat_message (solver,
// "parsed 'p cnf %d %" PRIu64 "' header", variables, clauses);
*max_var_ptr = variables;
kissat_reserve (solver, variables);
uint64_t parsed = 0;
int lit = 0;
for (;;)
{
ch = NEXT ();
if (ch == ' ')
continue;
if (ch == '\t')
continue;
if (ch == '\n')
continue;
if (ch == '\r')
{
ch = NEXT ();
if (ch != '\n')
return "expected new-line after carriage-return";
continue;
}
if (ch == 'c')
{
while ((ch = NEXT ()) != '\n')
if (ch == EOF)
{
if (strict != PEDANTIC_PARSING)
break;
return "unexpected end-of-file in comment after header";
}
if (ch == EOF)
break;
continue;
}
if (ch == EOF)
break;
int sign;
if (ch == '-')
{
ch = NEXT ();
if (ch == EOF)
return "unexpected end-of-file after '-'";
if (ch == '\n')
return nonl (ch, "unexpected new-line after '-'", lineno_ptr);
if (!isdigit (ch))
return "expected digit after '-'";
if (ch == '0')
return "expected non-zero digit after '-'";
sign = -1;
}
else if (!isdigit (ch))
return "expected digit or '-'";
else
sign = 1;
assert (isdigit (ch));
int idx = ch - '0';
while (isdigit (ch = NEXT ()))
{
if (EXTERNAL_MAX_VAR / 10 < idx)
return "variable index too large";
idx *= 10;
const int digit = ch - '0';
if (EXTERNAL_MAX_VAR - digit < idx)
return "variable index too large";
idx += digit;
}
if (ch == EOF)
{
if (strict == PEDANTIC_PARSING)
{
if (idx)
return "unexpected end-of-file after literal";
else
return "unexpected end-of-file after trailing zero";
}
}
else if (ch == '\r')
{
ch = NEXT ();
if (ch != '\n')
return "expected new-line after carriage-return";
}
else if (ch == 'c')
{
while ((ch = NEXT ()) != '\n')
if (ch == EOF)
{
if (strict != PEDANTIC_PARSING)
break;
return "unexpected end-of-file in comment after literal";
}
}
else if (ch != ' ' && ch != '\t' && ch != '\n')
return "expected white space after literal";
if (strict != RELAXED_PARSING && idx > variables)
return nonl (ch, "maximum variable index exceeded "
TRY_RELAXED_PARSING, lineno_ptr);
if (idx)
{
assert (sign == 1 || sign == -1);
assert (idx != INT_MIN);
lit = sign * idx;
}
else
{
if (strict != RELAXED_PARSING && parsed == clauses)
return "too many clauses " TRY_RELAXED_PARSING;
parsed++;
lit = 0;
}
kissat_add (solver, lit);
}
if (lit)
return "trailing zero missing";
if (strict != RELAXED_PARSING && parsed < clauses)
{
if (parsed + 1 == clauses)
return "one clause missing " TRY_RELAXED_PARSING;
return "more than one clause missing " TRY_RELAXED_PARSING;
}
return 0;
}
const char *
kissat_parse_dimacs (kissat * solver,
strictness strict,
file * file, uint64_t * lineno_ptr, int *max_var_ptr)
{
const char *res;
START (parse);
res = parse_dimacs (solver, strict, file, lineno_ptr, max_var_ptr);
STOP (parse);
return res;
}