shithub: riscv

Download patch

ref: 87df80019e3676583f2d60d500179ddcfabab584
parent: d68417bc01ef1258e707d95d4785c189fcad5834
author: aiju <devnull@localhost>
date: Sat Mar 17 23:03:12 EDT 2018

add sat(1) command

--- /dev/null
+++ b/sys/src/cmd/sat.c
@@ -1,0 +1,303 @@
+#include <u.h>
+#include <libc.h>
+#include <sat.h>
+#include <bio.h>
+#include <ctype.h>
+
+typedef struct Trie Trie;
+typedef struct Var Var;
+Biobuf *bin, *bout;
+
+struct Trie {
+	u64int hash;
+	Trie *c[2];
+	uchar l;
+};
+struct Var {
+	Trie trie;
+	char *name;
+	int n;
+	Var *next;
+};
+Trie *root;
+Var *vlist, **vlistp = &vlist;
+int varctr;
+
+static void*
+emalloc(ulong n)
+{
+	void *v;
+	
+	v = malloc(n);
+	if(v == nil) sysfatal("malloc: %r");
+	setmalloctag(v, getcallerpc(&n));
+	memset(v, 0, n);
+	return v;
+}
+
+u64int
+hash(char *s)
+{
+	u64int h;
+	
+	h = 0xcbf29ce484222325ULL;
+	for(; *s != 0; s++){
+		h ^= *s;
+		h *= 0x100000001b3ULL;
+	}
+	return h;
+}
+
+int
+ctz(u64int d)
+{
+	int r;
+	
+	d &= -d;
+	r = 0;
+	if((int)d == 0) r += 32, d >>= 32;
+	r += ((d & 0xffff0000) != 0) << 4;
+	r += ((d & 0xff00ff00) != 0) << 3;
+	r += ((d & 0xf0f0f0f0) != 0) << 2;
+	r += ((d & 0xcccccccc) != 0) << 1;
+	r += ((d & 0xaaaaaaaa) != 0);
+	return r;
+}
+
+Trie *
+trieget(u64int h)
+{
+	Trie *t, *s, **tp;
+	u64int d;
+	
+	tp = &root;
+	for(;;){
+		t = *tp;
+		if(t == nil){
+			t = emalloc(sizeof(Var));
+			t->hash = h;
+			t->l = 64;
+			*tp = t;
+			return t;
+		}
+		d = (h ^ t->hash) << 64 - t->l >> 64 - t->l;
+		if(d == 0 || t->l == 0){
+			if(t->l == 64)
+				return t;
+			tp = &t->c[h >> t->l & 1];
+			continue;
+		}
+		s = emalloc(sizeof(Trie));
+		s->hash = h;
+		s->l = ctz(d);
+		s->c[t->hash >> s->l & 1] = t;
+		*tp = s;
+		tp = &s->c[h >> s->l & 1];
+	}
+}
+
+Var *
+varget(char *n)
+{
+	Var *v, **vp;
+	
+	v = (Var*) trieget(hash(n));
+	if(v->name == nil){
+	gotv:
+		v->name = strdup(n);
+		v->n = ++varctr;
+		*vlistp = v;
+		vlistp = &v->next;
+		return v;
+	}
+	if(strcmp(v->name, n) == 0)
+		return v;
+	for(vp = (Var**)&v->trie.c[0]; (v = *vp) != nil; vp = (Var**)&v->trie.c[0])
+		if(strcmp(v->name, n) == 0)
+			return v;
+	v = emalloc(sizeof(Var));
+	*vp = v;
+	goto gotv;
+}
+
+static int
+isvarchar(int c)
+{
+	return isalnum(c) || c == '_' || c == '-' || c >= 0x80;
+}
+
+char lexbuf[512];
+enum { TEOF = -1, TVAR = -2 };
+int peektok;
+
+int
+lex(void)
+{
+	int c;
+	char *p;
+	
+	if(peektok != 0){
+		c = peektok;
+		peektok = 0;
+		return c;
+	}
+	do
+		c = Bgetc(bin);
+	while(c >= 0 && isspace(c) && c != '\n');
+	if(c == '#'){
+		do
+			c = Bgetc(bin);
+		while(c >= 0 && c != '\n');
+		if(c < 0) return TEOF;
+		c = Bgetc(bin);
+	}
+	if(c < 0) return TEOF;
+	if(isvarchar(c)){
+		p = lexbuf;
+		*p++ = c;
+		while(c = Bgetc(bin), c >= 0 && isvarchar(c))
+			if(p < lexbuf + sizeof(lexbuf) - 1)
+				*p++ = c;
+		*p = 0;
+		Bungetc(bin);
+		return TVAR;
+	}
+	return c;
+}
+
+void
+superman(int t)
+{
+	peektok = t;
+}
+
+int
+clause(SATSolve *s)
+{
+	int t;
+	int n;
+	int not, min, max;
+	char *p;
+	static int *clbuf, nclbuf;
+	
+	n = 0;
+	not = 1;
+	min = -1;
+	max = -1;
+	for(;;)
+		switch(t = lex()){
+		case '[':
+			t = lex();
+			if(t == TVAR){
+				min = strtol(lexbuf, &p, 10);
+				if(p == lexbuf || *p != 0 || min < 0) goto syntax;
+				t = lex();
+			}else
+				min = 0;
+			if(t == ']'){
+				max = min;
+				break;
+			}
+			if(t != ',') goto syntax;
+			t = lex();
+			if(t == TVAR){
+				max = strtol(lexbuf, &p, 10);
+				if(p == lexbuf || *p != 0 || max < 0) goto syntax;
+				t = lex();
+			}else
+				max = -1;
+			if(t != ']') goto syntax;
+			break;
+		case TVAR:
+			if(n == nclbuf){
+				clbuf = realloc(clbuf, (nclbuf + 32) * sizeof(int));
+				nclbuf += 32;
+			}
+			clbuf[n++] = not * varget(lexbuf)->n;
+			not = 1;
+			break;
+		case '!':
+			not *= -1;
+			break;
+		case TEOF:
+		case '\n':
+		case ';':
+			goto out;
+		default:
+			sysfatal("unexpected token %d", t);
+		}
+out:
+	if(n != 0)
+		if(min >= 0)
+			satrange1(s, clbuf, n, min, max< 0 ? n : max);
+		else
+			satadd1(s, clbuf, n);
+	return t != TEOF;
+syntax:
+	sysfatal("syntax error");
+	return 0;
+}
+
+int oneflag, multiflag;
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-1m] [file]\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	SATSolve *s;
+	Var *v;
+	
+	ARGBEGIN {
+	case '1': oneflag++; break;
+	case 'm': multiflag++; break;
+	default: usage();
+	} ARGEND;
+	
+	switch(argc){
+	case 0:
+		bin = Bfdopen(0, OREAD);
+		break;
+	case 1:
+		bin = Bopen(argv[0], OREAD);
+		break;
+	default: usage();
+	}
+	if(bin == nil) sysfatal("Bopen: %r");
+	s = satnew();
+	if(s == nil) sysfatal("satnew: %r");
+	while(clause(s))
+		;
+	if(multiflag){	
+		bout = Bfdopen(1, OWRITE);
+		while(satmore(s) > 0){
+			for(v = vlist; v != nil; v = v->next)
+				if(satval(s, v->n) > 0)
+					Bprint(bout, "%s ", v->name);
+			Bprint(bout, "\n");
+			Bflush(bout);
+		}
+	}else if(oneflag){
+		if(satsolve(s) == 0)
+			exits("unsat");
+		bout = Bfdopen(1, OWRITE);
+		for(v = vlist; v != nil; v = v->next)
+			if(satval(s, v->n) > 0)
+				Bprint(bout, "%s ", v->name);
+		Bprint(bout, "\n");
+		Bflush(bout);
+	}else{
+		if(satsolve(s) == 0)
+			exits("unsat");
+		bout = Bfdopen(1, OWRITE);
+		for(v = vlist; v != nil; v = v->next)
+			Bprint(bout, "%s %d\n", v->name, satval(s, v->n));
+		Bflush(bout);
+	}
+	exits(nil);
+}