Added midterm simulation "bexp"
This commit is contained in:
parent
63d93bb6c3
commit
b83a7d9378
3 changed files with 332 additions and 0 deletions
122
bexp/bexp.c
Normal file
122
bexp/bexp.c
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
// vim: set ts=4 sw=4 et tw=80:
|
||||||
|
|
||||||
|
#include "bexp.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static int value_length(const value* val);
|
||||||
|
|
||||||
|
inline int value_length(const value* val) {
|
||||||
|
return val->end - val->begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef int(*compute_func)(char*, int, int, int*);
|
||||||
|
|
||||||
|
int bexp_loop(value* result, const expression* ex, compute_func compute) {
|
||||||
|
const char* end1 = ex->value1.end;
|
||||||
|
const char* end2 = ex->value2.end;
|
||||||
|
|
||||||
|
char* l1 = ex->value1.begin;
|
||||||
|
char* l2 = (ex->op == NOT || ex->op == COMPLEMENT) ? NULL :
|
||||||
|
ex->value2.begin;
|
||||||
|
|
||||||
|
int acc = 0;
|
||||||
|
|
||||||
|
char* r = result->begin;
|
||||||
|
|
||||||
|
while (l1 < end1 || (l2 != NULL && l2 < end2)) {
|
||||||
|
if (r == result->end) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int a = l1 < end1 ? *l1 - '0' : 0;
|
||||||
|
const int b = l2 != NULL && l2 < end2 ? *l2 - '0' : 0;
|
||||||
|
|
||||||
|
*r = '0';
|
||||||
|
|
||||||
|
if (compute(r, a, b, &acc)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex->op != GREATER_THAN && ex->op != LESS_THAN && ex->op != NOT)
|
||||||
|
r++;
|
||||||
|
l1++;
|
||||||
|
if (l2 != NULL) l2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acc == 1) {
|
||||||
|
if (r == result->end) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
*r = '1';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int compute_and(char* r, int a, int b, int* _) { *r += a && b; return 0; }
|
||||||
|
int compute_or(char* r, int a, int b, int* _) { *r += a && b; return 0; }
|
||||||
|
int compute_xor(char* r, int a, int b, int* _) { *r += a && b; return 0; }
|
||||||
|
int compute_gt(char* r, int a, int b, int* _) { *r += a > b; return a != b; }
|
||||||
|
int compute_lt(char* r, int a, int b, int* _) { *r += a < b; return a != b; }
|
||||||
|
|
||||||
|
int compute_plus(char* r, int a, int b, int* c) {
|
||||||
|
*r += a ^ b ^ *c;
|
||||||
|
*c = a && b || ((a ^ b) && *c);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int compute_compl(char* r, int a, int _, int* __) { *r = !a; return 0; }
|
||||||
|
int compute_not(char* r, int a, int _, int* __) { *r = !a; return a; }
|
||||||
|
|
||||||
|
compute_func bexp_compute(const operator_t op) {
|
||||||
|
switch (op) {
|
||||||
|
case AND: return compute_and;
|
||||||
|
case OR: return compute_or;
|
||||||
|
case XOR: return compute_xor;
|
||||||
|
case PLUS: return compute_plus;
|
||||||
|
case GREATER_THAN: return compute_gt;
|
||||||
|
case LESS_THAN: return compute_lt;
|
||||||
|
case NOT: return compute_not;
|
||||||
|
case COMPLEMENT: return compute_compl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int bexp_length(const expression* ex) {
|
||||||
|
switch (ex->op) {
|
||||||
|
case AND:
|
||||||
|
case OR:
|
||||||
|
case XOR: {
|
||||||
|
const int l1 = value_length(&ex->value1);
|
||||||
|
const int l2 = value_length(&ex->value2);
|
||||||
|
return l1 > l2 ? l1 : l2;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PLUS: {
|
||||||
|
const int l1 = value_length(&ex->value1);
|
||||||
|
const int l2 = value_length(&ex->value2);
|
||||||
|
|
||||||
|
// handle overflow
|
||||||
|
if (l1 == l2 && l1 > 0 &&
|
||||||
|
*(ex->value1.end - 1) == '1' &&
|
||||||
|
*(ex->value2.end - 1) == '1') {
|
||||||
|
return l1 + 1;
|
||||||
|
} else {
|
||||||
|
return l1 > l2 ? l1 : l2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case GREATER_THAN:
|
||||||
|
case LESS_THAN:
|
||||||
|
case NOT:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case COMPLEMENT:
|
||||||
|
return value_length(&ex->value1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int bexp_evaluate(value* result, expression* ex) {
|
||||||
|
return bexp_loop(result, ex, bexp_compute(ex->op));
|
||||||
|
}
|
||||||
|
|
59
bexp/bexp.h
Normal file
59
bexp/bexp.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#ifndef BEXP_H_INCLUDED
|
||||||
|
#define BEXP_H_INCLUDED
|
||||||
|
|
||||||
|
/* A binary value expressed as a sequence of '0' and '1' characters,
|
||||||
|
* the sequence starts at the character pointed to by begin, and ends
|
||||||
|
* at the character right before the one pointed to by end. Thus a
|
||||||
|
* "null" value can be represented as an empty sequence where
|
||||||
|
* begin==end. The first character, pointed to by begin, represents
|
||||||
|
* the least-significant bit. All the bits following the most
|
||||||
|
* significant one specified in the sequence are assumed to be 0. A
|
||||||
|
* valid value must contain only '0' and '1' characters.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
char * begin; /* pointer to least significant bit */
|
||||||
|
char * end; /* pointer to one-past most significant bit */
|
||||||
|
} value;
|
||||||
|
|
||||||
|
/* Identifiers for the operators we can use on binary values
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/* Binary operators: */
|
||||||
|
AND, /* & */
|
||||||
|
OR, /* | */
|
||||||
|
XOR, /* ^ */
|
||||||
|
PLUS, /* + */
|
||||||
|
GREATER_THAN, /* > */
|
||||||
|
LESS_THAN, /* < */
|
||||||
|
/* Unary operators: */
|
||||||
|
NOT, /* ! logical negation: value==0 => 1, otherwise 0 */
|
||||||
|
COMPLEMENT, /* ~ complement: bitwise not */
|
||||||
|
} operator_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
operator_t op;
|
||||||
|
value value1; /* first operand */
|
||||||
|
value value2; /* second operand,
|
||||||
|
ignored if op is a unary operator. */
|
||||||
|
} expression;
|
||||||
|
|
||||||
|
/* Return the length (in characters) of the result of the given
|
||||||
|
* expression, without necessarily computing that expression. This
|
||||||
|
* can be used to allocate the space necessary to store the result.
|
||||||
|
* Return -1 in case of error, for example if the given expression
|
||||||
|
* contains an unknown operator.
|
||||||
|
*/
|
||||||
|
extern int bexp_length(const expression * ex);
|
||||||
|
|
||||||
|
/* Evaluates a given expression. The space in which to store the
|
||||||
|
* result must be allocated by the caller. Thus result->begin must
|
||||||
|
* point to the beginning of the allocated space while result->end
|
||||||
|
* points to one-past the end. Return 1 upon success, or 0 upon
|
||||||
|
* failure, for example if the given expression is not valid or if
|
||||||
|
* the space provided by the caller is insufficient to store the
|
||||||
|
* result. If the allocated space is larged than necessary, this
|
||||||
|
* function must adjust the length of the result sequence.
|
||||||
|
*/
|
||||||
|
extern int bexp_evaluate(value * result, expression * ex);
|
||||||
|
|
||||||
|
#endif
|
151
bexp/bexp_calculator.c
Normal file
151
bexp/bexp_calculator.c
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
// vim: set ts=4 sw=4 et tw=80:
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "bexp.h"
|
||||||
|
#include "ctype.h"
|
||||||
|
|
||||||
|
typedef struct stack {
|
||||||
|
value first;
|
||||||
|
struct stack* next;
|
||||||
|
char container[];
|
||||||
|
} stack_t;
|
||||||
|
|
||||||
|
stack_t* tos = NULL;
|
||||||
|
|
||||||
|
void read_value();
|
||||||
|
void read_command();
|
||||||
|
void discard();
|
||||||
|
|
||||||
|
void discard() {
|
||||||
|
fprintf(stderr, "Value is malformed. Discarding until space...\n");
|
||||||
|
while(isspace(getchar()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_word() {
|
||||||
|
char c;
|
||||||
|
while (isspace(c = getchar()));
|
||||||
|
ungetc(c, stdin);
|
||||||
|
if (c == '0' || c == '1') {
|
||||||
|
read_value();
|
||||||
|
} else {
|
||||||
|
read_command();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_value() {
|
||||||
|
int str_size = 10;
|
||||||
|
stack_t* new = malloc(sizeof(stack_t) + str_size * sizeof(char));
|
||||||
|
if (!new) {
|
||||||
|
perror("Cannot allocate new stack element");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new->next = tos;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
char c;
|
||||||
|
while(!isspace(c = getchar())) {
|
||||||
|
if (c != '0' || c != '1') {
|
||||||
|
free(new);
|
||||||
|
discard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new->container[count++] = c;
|
||||||
|
|
||||||
|
if (str_size == count) {
|
||||||
|
str_size *= 2;
|
||||||
|
new = realloc(new, sizeof(stack_t) + str_size * sizeof(char));
|
||||||
|
if (!new) {
|
||||||
|
perror("Cannot allocate new stack element");
|
||||||
|
free(new);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new->first.begin = new->container;
|
||||||
|
new->first.end = new->container + count;
|
||||||
|
tos = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ensure(char* str) {
|
||||||
|
while (str) {
|
||||||
|
if (tolower(getchar()) != *str) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_value(const value* val) {
|
||||||
|
char* v = val->begin;
|
||||||
|
while (v != val->end) putchar(*(v++));
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_command() {
|
||||||
|
operator_t op;
|
||||||
|
switch(getchar()) {
|
||||||
|
case '&': op = AND; break;
|
||||||
|
case '|': op = OR; break;
|
||||||
|
case '^': op = XOR; break;
|
||||||
|
case '+': op = PLUS; break;
|
||||||
|
case '>': op = GREATER_THAN; break;
|
||||||
|
case '<': op = LESS_THAN; break;
|
||||||
|
case '!': op = NOT; break;
|
||||||
|
case '~': op = COMPLEMENT; break;
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
if (!ensure("op")) {
|
||||||
|
discard();
|
||||||
|
} else {
|
||||||
|
if (tos == NULL) {
|
||||||
|
printf("empty\n");
|
||||||
|
} else {
|
||||||
|
print_value(&(tos->first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 'p':
|
||||||
|
case 'P':
|
||||||
|
if (!ensure("op")) {
|
||||||
|
discard();
|
||||||
|
} else {
|
||||||
|
if (tos == NULL) {
|
||||||
|
printf("empty\n");
|
||||||
|
} else {
|
||||||
|
print_value(&(tos->first));
|
||||||
|
stack_t* t = tos;
|
||||||
|
tos = tos->next;
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
default: discard(); return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int binary = op != NOT && op != COMPLEMENT;
|
||||||
|
|
||||||
|
if (tos == NULL || (binary && tos->next == NULL)) {
|
||||||
|
printf("too few values on stack\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
expression_t ex = { op, tos->value, binary ? tos->next->value : NULL };
|
||||||
|
int length = bexp_length(&ex);
|
||||||
|
|
||||||
|
char* result = malloc(sizeof(stack_t) + sizeof(char) * length);
|
||||||
|
if (!result) {
|
||||||
|
perror("Cannot allocate space for result");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
value v_result = { result, result + length };
|
||||||
|
|
||||||
|
bexp_evaluate(&v_result, &ex);
|
||||||
|
stack_t
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Reference in a new issue