bool.y (9103B)
1 /* This program is licensed under the terms of GNU GPL v3 or (at your option) 2 * any later version. Copyright (C) 2026 Страхиња Радић. 3 * See the file LICENSE for exact copyright and license details. */ 4 5 %{ 6 #include "bool.h" 7 %} 8 9 %union { 10 int ident_id; 11 struct expr_node* node_ptr; 12 } 13 14 %left IMPL 15 %left '|' 16 %left '^' 17 %left '&' 18 %nonassoc '~' 19 20 %token <ident_id> IDENT 21 %type <node_ptr> expr 22 23 %{ 24 #include <errno.h> 25 #include <stdarg.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 #include "version.h" 31 32 #define IDS_DELTA 100 33 #define COPYRIGHT \ 34 (" This program is licensed under the terms of GNU GPL v3" \ 35 " or (at your option)\n" \ 36 " any later version. Copyright (C) 2026 Strahinya Radich.\n" \ 37 " See the file LICENSE for exact copyright and license " \ 38 "details.") 39 #define YYDEBUG 1 40 41 static char** ids = NULL; 42 static signed char* vals = NULL; 43 static int ids_size = 0; 44 static int num_ids = 0; 45 static int debug = 0; 46 47 extern FILE* yyin; 48 int colno = 1, lineno = 1; 49 50 void yydbg(const char* format, ...); 51 void yyerror(const char* format, ...); 52 53 int add_id(const char* id); 54 char* get_id(const int index); 55 signed char get_val(const int index); 56 int get_index(const char* id); 57 struct expr_node* new_expr(const enum NodeType node_type, const enum Operator 58 operator, const int nargs, ...); 59 static void print_node(const int level, const int debug_only, struct expr_node* node); 60 static int simulate(const int index); 61 static void usage(void); 62 static void version(const int full); 63 64 extern int yylex(void); 65 66 #define NTN(id) [id] = #id 67 68 const char* node_type_ids[] = { 69 NTN(NT_IDENT), 70 NTN(NT_UNARY), 71 NTN(NT_BINARY) 72 }; 73 74 const char* operator_images[] = { 75 [OP_NONE] = "", 76 [OP_OR] = "OR", 77 [OP_AND] = "AND", 78 [OP_XOR] = "XOR", 79 [OP_NOT] = "NOT", 80 [OP_IMPL] = "IMPL" 81 }; 82 83 static struct expr_node* root = NULL; 84 85 void 86 yydbg(const char* format, ...) 87 { 88 va_list ap; 89 char buf[1024]; 90 if (!debug) 91 return; 92 va_start(ap, format); 93 vsnprintf(buf, sizeof buf, format, ap); 94 fprintf(stderr, "DEBUG: %s\n", buf); 95 va_end(ap); 96 } 97 98 void 99 yyerror(const char* format, ...) 100 { 101 va_list ap; 102 char buf[1024]; 103 va_start(ap, format); 104 vsnprintf(buf, sizeof buf, format, ap); 105 fprintf(stderr, "%s:%d:%d: %s\n", PROGNAME, lineno, colno, buf); 106 va_end(ap); 107 } 108 109 int 110 add_id(const char* id) 111 { 112 char** tempi = NULL; 113 signed char* tempv = NULL; 114 if (num_ids >= ids_size) 115 { 116 tempi = realloc(ids, (ids_size + IDS_DELTA) * sizeof(char*)); 117 if (!tempi) 118 goto add_id_realloc_error; 119 ids = tempi; 120 tempv = realloc(vals, (ids_size + IDS_DELTA)); 121 if (!tempv) 122 goto add_id_realloc_error; 123 vals = tempv; 124 ids_size += IDS_DELTA; 125 } 126 ids[num_ids++] = strdup(id); 127 vals[num_ids-1] = 0; 128 return num_ids-1; 129 130 add_id_realloc_error: 131 perror("realloc"); 132 exit(errno); 133 } 134 135 char* 136 get_id(const int index) 137 { 138 if (index >= 0 && index < num_ids) 139 return ids[index]; 140 return "N/A"; 141 } 142 143 signed char 144 get_val(const int index) 145 { 146 if (index >= 0 && index < num_ids) 147 return vals[index]; 148 return -1; 149 } 150 151 int 152 get_index(const char* id) 153 { 154 int idx = 0; 155 int found = 0; 156 while (!found && idx < num_ids) 157 { 158 if (!strcmp(ids[idx], id)) 159 { 160 found = 1; 161 continue; 162 } 163 idx++; 164 } 165 return found ? idx : -1; 166 } 167 168 struct expr_node* 169 new_expr(const enum NodeType node_type, const enum Operator operator, 170 const int nargs, ...) 171 { 172 va_list ap; 173 struct expr_node* np = NULL; 174 175 va_start(ap, nargs); 176 if (!(np = malloc(sizeof(struct expr_node)))) 177 goto new_expr_malloc_error; 178 np->type = node_type; 179 switch (node_type) 180 { 181 case NT_UNARY: 182 if (!(np->expr.unary = malloc(sizeof(struct expr_unary)))) 183 goto new_expr_malloc_error; 184 if (!(np->expr.unary->arg = va_arg(ap, struct expr_node*))) 185 goto new_expr_va_arg_error; 186 np->expr.unary->operator = operator; 187 break; 188 case NT_BINARY: 189 if (!(np->expr.binary = malloc(sizeof(struct expr_binary)))) 190 goto new_expr_malloc_error; 191 if (!(np->expr.binary->args[0] = va_arg(ap, struct expr_node*))) 192 goto new_expr_va_arg_error; 193 if (!(np->expr.binary->args[1] = va_arg(ap, struct expr_node*))) 194 goto new_expr_va_arg_error; 195 np->expr.binary->operator = operator; 196 break; 197 case NT_IDENT: 198 default: 199 if (!(np->expr.ident = malloc(sizeof(struct expr_ident)))) 200 goto new_expr_malloc_error; 201 np->expr.ident->id = va_arg(ap, int); 202 } 203 va_end(ap); 204 return np; 205 206 new_expr_malloc_error: 207 perror("new_expr"); 208 exit(errno); 209 return NULL; 210 211 new_expr_va_arg_error: 212 yyerror("va_arg is NULL"); 213 exit(ERR_VA_ARG_NULL); 214 return NULL; 215 } 216 217 void 218 print_node(const int level, const int debug_only, struct expr_node* node) 219 { 220 if ((debug_only && !debug) || !node) 221 return; 222 for (int i = 0; i < level; i++) 223 fprintf(debug_only && debug ? stderr : stdout, "\t"); 224 switch (node->type) 225 { 226 case NT_UNARY: 227 //printf("%s { ", operator_images[node->expr.unary->operator]); 228 fprintf(debug_only && debug ? stderr : stdout, 229 "%s\n", operator_images[node->expr.unary->operator]); 230 print_node(level+1, debug_only, node->expr.unary->arg); 231 //printf(" }"); 232 break; 233 case NT_BINARY: 234 //printf("{ "); 235 fprintf(debug_only && debug ? stderr : stdout, 236 "%s\n", operator_images[node->expr.binary->operator]); 237 print_node(level+1, debug_only, node->expr.binary->args[0]); 238 //printf(" %s ", operator_images[node->expr.binary->operator]); 239 print_node(level+1, debug_only, node->expr.binary->args[1]); 240 //printf(" }"); 241 break; 242 case NT_IDENT: 243 default: 244 fprintf(debug_only && debug ? stderr : stdout, 245 "[ID(%d) = \"%s\"]\n", 246 node->expr.ident->id, 247 get_id(node->expr.ident->id)); 248 } 249 } 250 251 static int 252 evaluate(const struct expr_node* node) 253 { 254 int result = -1; 255 switch (node->type) 256 { 257 case NT_UNARY: 258 switch (node->expr.unary->operator) 259 { 260 case OP_NOT: 261 result = !evaluate(node->expr.unary->arg); 262 break; 263 default:; 264 } 265 break; 266 case NT_BINARY: 267 switch (node->expr.binary->operator) 268 { 269 case OP_AND: 270 result = evaluate(node->expr.binary->args[0]) 271 & evaluate(node->expr.binary->args[1]); 272 break; 273 case OP_OR: 274 result = evaluate(node->expr.binary->args[0]) 275 | evaluate(node->expr.binary->args[1]); 276 break; 277 case OP_XOR: 278 result = evaluate(node->expr.binary->args[0]) 279 ^ evaluate(node->expr.binary->args[1]); 280 break; 281 case OP_IMPL: 282 result = !evaluate(node->expr.binary->args[0]) 283 | evaluate(node->expr.binary->args[1]); 284 break; 285 default:; 286 } 287 break; 288 case NT_IDENT: 289 result = get_val(node->expr.ident->id); 290 break; 291 default:; 292 } 293 return result; 294 } 295 296 static int 297 simulate(const int index) 298 { 299 int ii; 300 signed char val; 301 if (index >= num_ids) 302 return 0; 303 for (val = 0; val < 2; val++) 304 { 305 vals[index] = val; 306 simulate(index+1); 307 if (index+1 == num_ids) 308 { 309 for (ii = 0; ii < num_ids; ii++) 310 printf("%c\t", get_val(ii) ? 'T' : 'F'); 311 printf("%c\n", evaluate(root) ? 'T' : 'F'); 312 } 313 } 314 return 1; 315 } 316 317 static void 318 usage(void) 319 { 320 puts("Usage: " PROGNAME " [-dhtVv] [file]"); 321 } 322 323 static void 324 version(const int full) 325 { 326 printf("%s %s, committed on %s\n", PROGNAME, VERSION, DATE); 327 if (full) 328 puts(COPYRIGHT); 329 } 330 331 %} 332 333 %% 334 335 expr: IDENT { $$ = new_expr(NT_IDENT, OP_NONE, 1, $1); 336 print_node(0, 1, $$); 337 // replace the root with $$ 338 root = $$; 339 } 340 | expr '|' expr { $$ = new_expr(NT_BINARY, OP_OR, 2, $1, $3); 341 print_node(0, 1, $$); 342 // replace the root with $$ == OR($1, $3)... 343 root = $$; 344 } 345 | expr '&' expr { $$ = new_expr(NT_BINARY, OP_AND, 2, $1, $3); 346 print_node(0, 1, $$); 347 root = $$; 348 } 349 | expr '^' expr { $$ = new_expr(NT_BINARY, OP_XOR, 2, $1, $3); 350 print_node(0, 1, $$); 351 root = $$; 352 } 353 | expr IMPL expr 354 { $$ = new_expr(NT_BINARY, OP_IMPL, 2, $1, $3); 355 print_node(0, 1, $$); 356 root = $$; 357 } 358 | '~' expr { $$ = new_expr(NT_UNARY, OP_NOT, 1, $2); 359 print_node(0, 1, $$); 360 root = $$; 361 } 362 | '(' expr ')' { $$ = $2; 363 print_node(0, 1, $$); 364 root = $$; 365 } 366 ; 367 368 %% 369 370 int 371 main(int argc, char** argv) 372 { 373 int ch; 374 int showtree = 0; 375 int ididx; 376 int result; 377 378 ids_size = IDS_DELTA; 379 num_ids = 0; 380 ids = malloc(ids_size * sizeof(char*)); 381 if (!ids) 382 goto main_malloc_error; 383 ids[0] = NULL; 384 vals = malloc(ids_size); 385 if (!vals) 386 goto main_malloc_error; 387 vals[0] = 0; 388 389 //yydebug = 1; 390 if ((ch = getopt(argc, argv, ":dhtVv")) != -1) 391 { 392 switch (ch) 393 { 394 case 'd': 395 debug = 1; 396 break; 397 case 'h': 398 usage(); 399 exit(0); 400 case 't': 401 showtree = 1; 402 break; 403 case 'V': 404 version(1); 405 exit(0); 406 case 'v': 407 version(0); 408 exit(0); 409 case '?': 410 yyerror("Invalid parameter: -%c", optopt); 411 exit(ERR_BAD_CL_ARG); 412 default:; 413 } 414 } 415 416 if (argc > optind && (argv[optind][0] != '-' || argv[optind][1] != 0)) 417 { 418 if (!(yyin = fopen(argv[optind], "r"))) 419 { 420 perror("fopen"); 421 exit(errno); 422 } 423 } 424 result = yyparse(); 425 if (yyin && yyin != stdin) 426 fclose(yyin); 427 428 if (!root || result) 429 exit(ERR_PARSE_ERROR); 430 431 if (showtree) 432 print_node(0, 0, root); 433 else 434 { 435 for (ididx = 0; ididx < num_ids; ididx++) 436 printf("%s\t", get_id(ididx)); 437 puts("Result"); 438 simulate(0); 439 } 440 exit(0); 441 442 main_malloc_error: 443 perror("malloc"); 444 exit(errno); 445 }