bool

Програм за тестирање логичких израза
git clone https://git.sr.ht/~strahinja/bool
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

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 }