aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/lexer.l1
-rw-r--r--src/main.c145
-rw-r--r--src/parser.y60
-rw-r--r--src/pinocchio.h7
-rw-r--r--src/wrapper.c27
-rw-r--r--src/wrapper.h11
7 files changed, 185 insertions, 68 deletions
diff --git a/Makefile b/Makefile
index 0972555..a33cbb5 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ MAKEFLAGS = -j8
CFLAGS = -O3 -march=native -mtune=native -pipe -Wall -Wextra -Wpedantic
target = pinocchio
-objs = src/lexer.o src/main.o src/parser.o
+objs = src/lexer.o src/main.o src/parser.o src/wrapper.o
all: $(target)
$(target): $(objs)
diff --git a/src/lexer.l b/src/lexer.l
index 832db79..befd30a 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -25,6 +25,7 @@ extern const char *current_file;
\<=>|⇔ { return EQUIV; }
\( { return OPAR; }
\) { return CPAR; }
+\| { return '|'; }
\n { return EOL; }
[a-zA-Z] {
diff --git a/src/main.c b/src/main.c
index 197f63a..d90bb96 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,3 +1,4 @@
+#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <getopt.h>
@@ -9,13 +10,16 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
#include "lexer.h"
#include "parser.h"
+#include "wrapper.h"
-#define MAXVARS (26 * 2)
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#define MAXVARS (26 * 2)
+
+#define lengthof(x) ((sizeof(x) / sizeof(*(x))))
#ifndef __has_builtin
# define __has_builtin(x) (0)
@@ -41,8 +45,8 @@ static tbl_style_t tflag = TS_UNSET;
const char *current_file;
-static void astprocess_cli(ast_t);
-static void astprocess_latex(ast_t);
+static void astprocess_cli(asts_t);
+static void astprocess_latex(asts_t);
static bool eqnsolve(eqn_t *, uint64_t, uint64_t);
static int eqnprint(eqn_t *);
static void eqnfree(eqn_t *);
@@ -77,11 +81,11 @@ main(int argc, char **argv)
while ((opt = getopt_long(argc, argv, "b:t:", longopts, NULL)) != -1) {
switch (opt) {
case 'b':
- if (strcmp(optarg, "alpha") == 0)
+ if (streq(optarg, "alpha"))
bflag = BS_ALPHA;
- else if (strcmp(optarg, "binary") == 0)
+ else if (streq(optarg, "binary"))
bflag = BS_BINARY;
- else if (strcmp(optarg, "symbols") == 0)
+ else if (streq(optarg, "symbols"))
bflag = BS_SYMBOLS;
else {
warnx("invalid bool style -- '%s'", optarg);
@@ -89,11 +93,11 @@ main(int argc, char **argv)
}
break;
case 't':
- if (strcmp(optarg, "ascii") == 0)
+ if (streq(optarg, "ascii"))
tflag = TS_ASCII;
- else if (strcmp(optarg, "latex") == 0)
+ else if (streq(optarg, "latex"))
tflag = TS_LATEX;
- else if (strcmp(optarg, "utf8") == 0)
+ else if (streq(optarg, "utf8"))
tflag = TS_UTF8;
else {
warnx("invalid table style -- '%s'", optarg);
@@ -109,7 +113,7 @@ usage:
}
if (tflag == TS_UNSET) {
- tflag = strcmp(nl_langinfo(CODESET), "UTF-8") == 0
+ tflag = streq(nl_langinfo(CODESET), "UTF-8")
? TS_UTF8 : TS_ASCII;
}
@@ -124,7 +128,7 @@ usage:
rv = EXIT_FAILURE;
}
} else for (int i = 0; i < argc; i++) {
- if (strcmp(argv[i], "-") == 0)
+ if (streq(argv[i], "-"))
yyin = stdin;
else if ((yyin = fopen(argv[i], "r")) == NULL) {
warn("fopen: %s", argv[i]);
@@ -141,13 +145,16 @@ usage:
}
void
-astprocess(ast_t a)
+astprocess(asts_t as)
{
- (tflag == TS_LATEX ? astprocess_latex : astprocess_cli)(a);
+ (tflag == TS_LATEX ? astprocess_latex : astprocess_cli)(as);
+ for (size_t i = 0; i < as.len; i++)
+ eqnfree(as.buf[i].eqn);
+ free(as.buf);
}
void
-astprocess_cli(ast_t a)
+astprocess_cli(asts_t as)
{
enum {
TBLVBAR,
@@ -174,39 +181,68 @@ astprocess_cli(ast_t a)
const char **tblsyms = tflag == TS_UTF8 ? tblsyms_utf8 : tblsyms_ascii;
+ uint64_t varmsk = as.buf[0].vars;
+ for (size_t i = 1; i < as.len; i++)
+ varmsk |= as.buf[i].vars;
+ int varcnt = popcnt(varmsk);
+
for (int i = 0; i < MAXVARS; i++) {
- if ((a.vars & UINT64_C(1)<<i) != 0)
+ if ((varmsk & UINT64_C(1)<<i) != 0)
printf("%c ", i < 26 ? i + 'A' : i + 'a' - 26);
}
- printf("%s ", tblsyms[TBLVBAR]);
- int eqnw = eqnprint(a.eqn);
- putchar('\n');
- int varcnt = popcnt(a.vars);
+ int *eqnws = xmalloc(sizeof(*eqnws) * as.len);
+
+ for (size_t i = 0; i < as.len; i++) {
+ printf("%s ", tblsyms[TBLVBAR]);
+ eqnws[i] = eqnprint(as.buf[i].eqn);
+ if (i < as.len - 1) {
+ eqnws[i]++;
+ putchar(' ');
+ }
+ }
+ putchar('\n');
for (int i = 0; i < varcnt*2; i++)
fputs(tblsyms[TBLHBAR], stdout);
fputs(tblsyms[TBLCROS], stdout);
- for (int i = 0; i <= eqnw; i++)
- fputs(tblsyms[TBLHBAR], stdout);
+ for (size_t i = 0; i < as.len; i++) {
+ for (int j = 0; j <= eqnws[i]; j++)
+ fputs(tblsyms[TBLHBAR], stdout);
+ if (i < as.len - 1)
+ fputs(tblsyms[TBLCROS], stdout);
+ }
+
putchar('\n');
for (uint64_t msk = 0; msk < (UINT64_C(1) << varcnt); msk++) {
for (int i = varcnt; i --> 0;)
printf("%s ", boolsyms[bflag][(bool)(msk & UINT64_C(1)<<i)]);
- int w = (eqnw & 1) == 0 ? eqnw / 2 : eqnw/2 + 1;
- printf("%s %*s\n",
- tblsyms[TBLVBAR],
- /* The symbols are encoded as 3 UTF-8 codepoints */
- w + (bflag == BS_SYMBOLS)*2,
- boolsyms[bflag][eqnsolve(a.eqn, a.vars, msk)]);
+
+ for (size_t i = 0; i < as.len; i++) {
+ int eqnw = eqnws[i];
+ int w = (eqnw & 1) == 0 ? eqnw / 2 : eqnw/2 + 1;
+ printf("%s %*s",
+ tblsyms[TBLVBAR],
+ /* The symbols are encoded as 3 UTF-8 codepoints */
+ w + (bflag == BS_SYMBOLS)*2,
+ boolsyms[bflag][eqnsolve(as.buf[i].eqn, varmsk, msk)]);
+ if (i < as.len - 1) {
+ if ((eqnw & 1) != 0)
+ w--;
+ for (int i = 0; i < w; i++)
+ putchar(' ');
+ }
+ }
+
+ putchar('\n');
}
- eqnfree(a.eqn);
+ free(eqnws);
}
void
-astprocess_latex(ast_t a)
+astprocess_latex(asts_t as)
{
static const char *boolsyms[][2] = {
[BS_ALPHA] = {"F", "T"},
@@ -215,33 +251,48 @@ astprocess_latex(ast_t a)
};
fputs("\\begin{displaymath}\n\t\\begin{array}{|", stdout);
- int varcnt = popcnt(a.vars);
+
+ uint64_t varmsk = as.buf[0].vars;
+ for (size_t i = 1; i < as.len; i++)
+ varmsk |= as.buf[i].vars;
+ int varcnt = popcnt(varmsk);
+
for (int i = 0; i < varcnt; i++) {
- if (i == 0)
- putchar('c');
- else
- fputs(" c", stdout);
+ if (i > 0)
+ putchar(' ');
+ putchar('c');
}
- fputs("|c|}\n\t\t", stdout);
+
+ for (size_t i = 0; i < as.len; i++)
+ fputs("|c", stdout);
+ fputs("|}\n\t\t", stdout);
for (int i = 0; i < MAXVARS; i++) {
- if ((a.vars & UINT64_C(1)<<i) != 0)
+ if ((varmsk & UINT64_C(1)<<i) != 0)
printf("%c & ", i < 26 ? i + 'A' : i + 'a' - 26);
}
- (void)eqnprint(a.eqn);
+ for (size_t i = 0; i < as.len; i++) {
+ (void)eqnprint(as.buf[i].eqn);
+ if (i < as.len - 1)
+ fputs(" & ", stdout);
+ }
puts("\\\\\n\t\t\\hline");
for (uint64_t msk = 0; msk < (UINT64_C(1) << varcnt); msk++) {
fputs("\t\t", stdout);
for (int i = varcnt; i --> 0;)
printf("%s & ", boolsyms[bflag][(bool)(msk & UINT64_C(1)<<i)]);
- printf("%s\\\\\n", boolsyms[bflag][eqnsolve(a.eqn, a.vars, msk)]);
+
+ for (size_t i = 0; i < as.len; i++) {
+ printf("%s", boolsyms[bflag][eqnsolve(as.buf[i].eqn, varmsk, msk)]);
+ if (i < as.len - 1)
+ fputs(" & ", stdout);
+ }
+ fputs("\\\\\n", stdout);
}
puts("\t\\end{array}\n\\end{displaymath}");
-
- eqnfree(a.eqn);
}
bool
@@ -252,6 +303,18 @@ eqnsolve(eqn_t *e, uint64_t vars, uint64_t msk)
int i = 0, bitnr = islower(e->ch) ? e->ch-'a'+26 : e->ch-'A';
for (int j = 0; j < bitnr; j++)
i += (bool)(vars & UINT64_C(1)<<j);
+
+ /* We have a bit of a problem, where if given the input
+ ‘a && b | b && c’, when extracting the value of ‘c’ we
+ actually extract the value of ‘a’ because MSK is backwards.
+
+ This means that if we have 3 variables (a, b, and c) and we
+ want to get the value of ‘c’, we need to extract bit 0 while
+ for ‘a’ we need bit 2. This tomfoolery here does the mapping
+ of the ‘logical’ index (i.e. {0, 1, 2} for {a, b, c}) to the
+ ‘real’ index (i.e. {2, 1, 0} for {a, b, c}). */
+ i = -i + popcnt(vars) - 1;
+
return msk & UINT64_C(1)<<i;
}
case OPAR:
diff --git a/src/parser.y b/src/parser.y
index e77af6f..e424068 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -6,10 +6,10 @@
#include "lexer.h"
#include "parser.h"
+#include "wrapper.h"
static ast_t mkunop(int, ast_t);
static ast_t mkbinop(int, ast_t, ast_t);
-static void *xmalloc(size_t);
static void yyerror(const char *);
extern const char *current_file;
@@ -20,8 +20,9 @@ extern const char *current_file;
}
%union {
- char ch;
- ast_t ast;
+ char ch;
+ ast_t ast;
+ asts_t asts;
}
%define parse.error verbose
@@ -33,7 +34,8 @@ extern const char *current_file;
%token NOT AND OR XOR IMPL
%token EQUIV OPAR CPAR EOL
%token<ch> IDENT
-%type<ast> line exp
+%type<ast> expr
+%type<asts> line exprs
%left OR
%left AND
@@ -46,34 +48,51 @@ extern const char *current_file;
input:
%empty
| input line {
- if ($2.eqn != NULL)
+ if ($2.len > 0)
astprocess($2);
}
;
line:
- EOL { $$.eqn = NULL; }
- | exp eol { $$ = $1; }
+ EOL { $$.len = 0; }
+ | exprs eol { $$ = $1; }
;
-eol: EOL | YYEOF;
+exprs:
+ expr {
+ $$.len = 1;
+ $$.cap = 8;
+ $$.buf = xmalloc(sizeof(*$$.buf) * $$.cap);
+ $$.buf[0] = $1;
+ }
+ | exprs '|' expr {
+ $$ = $1;
+ if ($$.len == $$.cap) {
+ $$.cap *= 2;
+ $$.buf = xrealloc($$.buf, sizeof(*$$.buf) * $$.cap);
+ }
+ $$.buf[$$.len++] = $3;
+ }
+ ;
-exp:
+expr:
IDENT {
$$.eqn = xmalloc(sizeof(eqn_t));
$$.eqn->type = IDENT;
$$.eqn->ch = $1;
$$.vars = 1 << (islower($1) ? $1-'a'+26 : $1-'A');
}
- | NOT exp { $$ = mkunop(NOT, $2); }
- | OPAR exp CPAR { $$ = mkunop(OPAR, $2); }
- | exp AND exp { $$ = mkbinop(AND, $1, $3); }
- | exp OR exp { $$ = mkbinop(OR, $1, $3); }
- | exp XOR exp { $$ = mkbinop(XOR, $1, $3); }
- | exp IMPL exp { $$ = mkbinop(IMPL, $1, $3); }
- | exp EQUIV exp { $$ = mkbinop(EQUIV, $1, $3); }
+ | NOT expr { $$ = mkunop(NOT, $2); }
+ | OPAR expr CPAR { $$ = mkunop(OPAR, $2); }
+ | expr AND expr { $$ = mkbinop(AND, $1, $3); }
+ | expr OR expr { $$ = mkbinop(OR, $1, $3); }
+ | expr XOR expr { $$ = mkbinop(XOR, $1, $3); }
+ | expr IMPL expr { $$ = mkbinop(IMPL, $1, $3); }
+ | expr EQUIV expr { $$ = mkbinop(EQUIV, $1, $3); }
;
+eol: EOL | YYEOF;
+
%%
ast_t
@@ -101,15 +120,6 @@ mkbinop(int op, ast_t lhs, ast_t rhs)
return a;
}
-void *
-xmalloc(size_t n)
-{
- void *p = malloc(n);
- if (p == NULL)
- err(1, "malloc");
- return p;
-}
-
void
yyerror(const char *s)
{
diff --git a/src/pinocchio.h b/src/pinocchio.h
index fb74f3c..1a25672 100644
--- a/src/pinocchio.h
+++ b/src/pinocchio.h
@@ -19,7 +19,12 @@ typedef struct {
uint64_t vars;
} ast_t;
-void astprocess(ast_t);
+typedef struct {
+ size_t len, cap;
+ ast_t *buf;
+} asts_t;
+
+void astprocess(asts_t);
void user_error(const char *, ...)
#if __GNUC__
__attribute__((format(printf, 1, 2)))
diff --git a/src/wrapper.c b/src/wrapper.c
new file mode 100644
index 0000000..16c6300
--- /dev/null
+++ b/src/wrapper.c
@@ -0,0 +1,27 @@
+#include <err.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+void *
+xmalloc(size_t n)
+{
+ void *p = malloc(n);
+ if (p == NULL)
+ err(1, "malloc");
+ return p;
+}
+
+void *
+xrealloc(void *p, size_t n)
+{
+ if ((p = realloc(p, n)) == NULL)
+ err(1, "realloc");
+ return p;
+}
+
+bool
+streq(const char *x, const char *y)
+{
+ return strcmp(x, y) == 0;
+}
diff --git a/src/wrapper.h b/src/wrapper.h
new file mode 100644
index 0000000..a57f71e
--- /dev/null
+++ b/src/wrapper.h
@@ -0,0 +1,11 @@
+#ifndef PINOCCHIO_WRAPPER_H
+#define PINOCCHIO_WRAPPER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+void *xmalloc(size_t);
+void *xrealloc(void *, size_t);
+bool streq(const char *, const char *);
+
+#endif /* !PINOCCHIO_WRAPPER_H */