Browse Source

Parsing of the expression tree is complete. The program can now be given an expression of any length and then construct an appropriate tree that preserves order of operations. Hexidecimal tokenizing appears to be broken.

long_to_char
Cameron Weinfurt 2 years ago
parent
commit
d21fe58a8d
  1. 16
      Makefile
  2. 13
      expr.c
  3. 20
      expr.h
  4. 44
      main.c
  5. 271
      parse.c
  6. 5
      parse.h
  7. 2
      token.c
  8. 4
      token.h

16
Makefile

@ -1,13 +1,19 @@
objs = main.o token.o expr.o
objs = main.o token.o expr.o parse.o
build: $(objs)
gcc -o infcalc $(objs)
gcc -o infcalc $(objs) -g
clean:
rm *.o infcalc
main.o: main.c expr.h
gcc -c main.c -o main.o
gcc -c main.c -o main.o -g
token.o: token.c token.h
gcc -c token.c -o token.o
gcc -c token.c -o token.o -g
expr.o: expr.c expr.h
gcc -c expr.c -o expr.o
gcc -c expr.c -o expr.o -g
parse.o: parse.c parse.h token.h expr.h
gcc -c parse.c -o parse.o -g

13
expr.c

@ -13,6 +13,7 @@ expr_t *bubble_expr(expr_t *t, expr_t *n) {
// Or is the current node the initial node?
else if (t->opcode == EXPR_NULL) {
n->left.data = t->right.data;
n->flags |= t->flags & EXFLAG_RNEG ? EXFLAG_LNEG : 0;
free(t);
return n;
}
@ -29,6 +30,8 @@ expr_t *bubble_expr(expr_t *t, expr_t *n) {
n->par = t;
t->right.expr = n;
t->flags |= EXFLAG_REXP;
n->flags |= t->flags & EXFLAG_RNEG ? EXFLAG_LNEG : 0;
t->flags &= ~EXFLAG_RNEG;
return t;
}
}
@ -54,3 +57,13 @@ void print_expr_tree(expr_t *t, int depth) {
fprintf(stderr, "%ld\n", t->right.data);
}
}
void destroy_expr(expr_t *e) {
if (e->flags & EXFLAG_LEXP) {
destroy_expr(e->left.expr);
}
if (e->flags & EXFLAG_REXP) {
destroy_expr(e->right.expr);
}
free(e);
}

20
expr.h

@ -9,16 +9,15 @@
#define EXFLAG_LNEG 0x4 // Negate the value on the left.
#define EXFLAG_RNEG 0x8 // Negate the value on the right.
#define EXFLAG_PAREN 0x10 // Override priority due to parenthesises.
#define EXFLAG_MOD1 0x20 // Modifers alter the operation so that similar
#define EXFLAG_MOD2 0x40 // priority operations are the same opcode.
#define EXFLAG_MOD 0x20 // For differentiating same priority operations.
#define EXFLAG_HEX 0x40 // When concatinating, multiply left side by 256.
#define EXPR_NULL 0 // Needed for the initial root node.
#define EXPR_ADD 1
#define EXPR_SUB 1 // EXFLAG_RNEG is set.
#define EXPR_MULT100 2 // MOD = 00
#define EXPR_MULT256 2 // MOD = 01
#define EXPR_MULT 2 // MOD = 10
#define EXPR_DIV 2 // MOD = 11
#define EXPR_ADD 1 // MOD = 0 RNEG = 0
#define EXPR_SUB 1 // MOD = 0 RNEG = 1
#define EXPR_CONCAT 1 // MOD = 1 RNEG = 0
#define EXPR_MULT 2 // MOD = 0
#define EXPR_DIV 2 // MOD = 1
#define EXPR_IPOW 3
typedef struct expr_t {
@ -26,16 +25,17 @@ typedef struct expr_t {
int opcode;
struct expr_t *par;
union {
long data;
unsigned long data;
struct expr_t *expr;
} left;
union {
long data;
unsigned long data;
struct expr_t *expr;
} right;
} expr_t;
expr_t *bubble_expr(expr_t *t, expr_t *n);
void print_expr_tree(expr_t *t, int depth);
void destroy_expr(expr_t *e);
#endif

44
main.c

@ -2,50 +2,18 @@
#include <stdlib.h>
#include "expr.h"
expr_t *init_expr(int o, int f, long n) {
expr_t *e = malloc(sizeof(expr_t));
e->opcode = o;
e->flags = f;
e->left.data = 0;
e->right.data = n;
return e;
}
#include "parse.h"
int main() {
expr_t *root, *ap, *m, *ex;
root = init_expr(EXPR_NULL, 0, 3);
ap = init_expr(EXPR_ADD, EXFLAG_PAREN, 2);
m = init_expr(EXPR_MULT, EXFLAG_MOD2, 4);
ex = init_expr(EXPR_IPOW, 0, 2);
print_expr_tree(root, 0);
fprintf(stderr, "-------------------\n");
root = bubble_expr(root, ap);
print_expr_tree(root, 0);
fprintf(stderr, "-------------------\n");
root = bubble_expr(root, ex);
print_expr_tree(root, 0);
fprintf(stderr, "-------------------\n");
root = bubble_expr(root, m);
print_expr_tree(root, 0);
fprintf(stderr, "-------------------\n");
}
/*int main() {
char *line = NULL;
size_t line_len = 0;
getline(&line,&line_len,stdin);
input_str = line;
int token;
while(token = tokenize())
printf("%d\n", token);
expr_t *e = parse(0);
free(line);
}*/
print_expr_tree(e, 0);
destroy_expr(e);
}

271
parse.c

@ -0,0 +1,271 @@
#include "parse.h"
long fromhex(const char *s) {
char c = *s & ~(0x20);
if (c >= 'A') return c - 'A' + 10;
return c - '0';
}
expr_t *parse_hex_int() {
const char *ptr = token_str + 2; // Skip the initial "0x" part
expr_t *num = malloc(sizeof(expr_t));
num->opcode = EXPR_NULL;
num->flags = num->left.data = 0;
num->par = NULL;
num->right.data = fromhex(ptr);
for (int d = 0; d < 16; ++d) {
ptr++;
if (ptr == input_str) return num;
num->right.data = num->right.data * 16 + fromhex(ptr);
}
ptr++;
while(ptr != input_str) {
expr_t *more_num = malloc(sizeof(expr_t));
more_num->opcode = EXPR_CONCAT;
more_num->flags = EXFLAG_MOD | EXFLAG_HEX;
more_num->left.data = 0;
more_num->right.data = *ptr - '0';
for (int d = 0; d < 16; ++d) {
ptr++;
if (ptr == input_str) return bubble_expr(num, more_num);
more_num->right.data = more_num->right.data * 16 + fromhex(ptr);
num = bubble_expr(num, more_num);
}
ptr++;
}
}
expr_t *parse_decimal_int() {
const char *ptr = token_str;
expr_t *num = malloc(sizeof(expr_t));
num->opcode = EXPR_NULL;
num->flags = num->left.data = 0;
num->par = NULL;
num->right.data = *ptr - '0';
for (int d = 0; d < 19; ++d) {
ptr++;
if (ptr == input_str) return num;
num->right.data = num->right.data * 10 + *ptr - '0';
}
ptr++;
while(ptr != input_str) {
expr_t *more_num = malloc(sizeof(expr_t));
more_num->opcode = EXPR_CONCAT;
more_num->flags = EXFLAG_MOD;
more_num->left.data = 0;
more_num->right.data = *ptr - '0';
for (int d = 0; d < 19; ++d) {
ptr++;
if (ptr == input_str) return bubble_expr(num, more_num);
more_num->right.data = more_num->right.data * 10 + *ptr - '0';
num = bubble_expr(num, more_num);
}
ptr++;
}
return num;
}
expr_t *parse_operation(int opcode) {
expr_t *num_expr;
switch (tokenize()) {
case TOK_NULL:
fprintf(stderr, "Expected expression, found end of data.\n");
return NULL;
case TOK_ERR:
fprintf(stderr, "Invalid token \"%c\".", *token_str);
return NULL;
case TOK_NUMDEC:
num_expr = parse_decimal_int();
break;
case TOK_NUMHEX:
num_expr = parse_hex_int();
num_expr->flags |= num_expr->opcode ? EXFLAG_PAREN : 0;
break;
case TOK_LPAREN:
num_expr = parse(1);
num_expr->flags |= EXFLAG_PAREN;
break;
case TOK_RPAREN:
fprintf(stderr, "Expected expression, found \"(\".\n");
return NULL;
case TOK_MINUS: ;
token_t t = tokenize();
if (t == TOK_NUMDEC) {
num_expr = parse_decimal_int();
num_expr->flags |= EXFLAG_RNEG;
break;
}
else if (t == TOK_NUMHEX) {
num_expr = parse_hex_int();
num_expr->flags |= EXFLAG_RNEG;
break;
}
case TOK_PLUS:
case TOK_STAR:
case TOK_FSLASH:
case TOK_CARROT:
fprintf(stderr, "Expected expression, found operator.\n");
return NULL;
}
if (num_expr->opcode) {
expr_t *add_expr = malloc(sizeof(expr_t));
add_expr->opcode = opcode;
add_expr->par = NULL;
add_expr->left.data = 0;
add_expr->flags = EXFLAG_REXP;
add_expr->right.expr = num_expr;
num_expr->flags |= EXFLAG_PAREN;
return add_expr;
}
else {
num_expr->opcode = opcode;
return num_expr;
}
}
expr_t *parse(char expect_rparen) {
expr_t *expr_tree;
// Construct initial expression.
switch (tokenize()) {
case TOK_NULL:
fprintf(stderr, "Expected expression, found end of data.\n");
return NULL;
case TOK_ERR:
fprintf(stderr, "Invalid token \"%c\".", *token_str);
return NULL;
case TOK_NUMDEC:
expr_tree = parse_decimal_int();
expr_tree->flags |= expr_tree->opcode ? EXFLAG_PAREN : 0;
break;
case TOK_NUMHEX:
expr_tree = parse_hex_int();
expr_tree->flags |= expr_tree->opcode ? EXFLAG_PAREN : 0;
break;
case TOK_LPAREN:
expr_tree = parse(1);
expr_tree->flags |= EXFLAG_PAREN;
break;
case TOK_RPAREN:
fprintf(stderr, "Expected expression, found \")\".\n");
return NULL;
case TOK_MINUS: ;
token_t t = tokenize();
if (t == TOK_NUMDEC) {
expr_tree = parse_decimal_int();
expr_tree->flags |= EXFLAG_RNEG;
break;
}
else if (t == TOK_NUMHEX) {
expr_tree = parse_hex_int();
expr_tree->flags |= EXFLAG_RNEG;
break;
}
case TOK_PLUS:
case TOK_STAR:
case TOK_FSLASH:
case TOK_CARROT:
fprintf(stderr, "Expected expression, found operator.\n");
return NULL;
}
// Continual construction of the expression tree.
while (1) {
switch (tokenize()) {
case TOK_NULL:
if (expect_rparen) {
fprintf(stderr, "Expected \")\", found end of data.\n");
destroy_expr(expr_tree);
return NULL;
}
else {
return expr_tree;
}
case TOK_ERR:
fprintf(stderr, "Invalid token \"%c\".", *token_str);
destroy_expr(expr_tree);
return NULL;
case TOK_NUMDEC:
case TOK_NUMHEX:
fprintf(stderr, "Expected operator, found number.\n");
destroy_expr(expr_tree);
return NULL;
case TOK_LPAREN:
fprintf(stderr, "Expected operator, found \"(\".\n");
destroy_expr(expr_tree);
return NULL;
case TOK_RPAREN:
if (expect_rparen) {
expr_tree->flags |= expr_tree->opcode ? EXFLAG_PAREN : 0;
return expr_tree;
}
else {
fprintf(stderr, "Expected operator, found \")\".\n");
destroy_expr(expr_tree);
return NULL;
}
case TOK_PLUS: ;
expr_t *a = parse_operation(EXPR_ADD);
if (a) {
expr_tree = bubble_expr(expr_tree, a);
}
else {
destroy_expr(expr_tree);
return NULL;
}
break;
case TOK_MINUS: ;
expr_t *s = parse_operation(EXPR_SUB);
if (s) {
s->flags ^= EXFLAG_RNEG;
expr_tree = bubble_expr(expr_tree, s);
}
else {
destroy_expr(expr_tree);
return NULL;
}
break;
case TOK_STAR: ;
expr_t *m = parse_operation(EXPR_MULT);
if (m) {
expr_tree = bubble_expr(expr_tree, m);
}
else {
destroy_expr(expr_tree);
return NULL;
}
break;
case TOK_FSLASH: ;
expr_t *d = parse_operation(EXPR_DIV);
if (d) {
d->flags |= EXFLAG_MOD;
expr_tree = bubble_expr(expr_tree, d);
}
else {
destroy_expr(expr_tree);
return NULL;
}
break;
case TOK_CARROT: ;
expr_t *ex = parse_operation(EXPR_IPOW);
if (ex) {
expr_tree = bubble_expr(expr_tree, ex);
}
else {
destroy_expr(expr_tree);
return NULL;
}
break;
}
}
}

5
parse.h

@ -1,8 +1,11 @@
#ifndef PARSEH
#define PARSEH
#include <stdlib.h>
#include "expr.h"
#include "token.h"
int parse(const char *str);
expr_t *parse(char expect_rparen);
#endif

2
token.c

@ -24,7 +24,7 @@ int tokenize() {
break;
case '0':
// Check if hex number.
if (*(input_str+1) & 0xDF == 'X' && ISHEX(*(input_str+2))) {
if ((*(input_str+1) == 'X' || (*(input_str+1) == 'x')) && ISHEX(*(input_str+2))) {
// Yes, munch hex digits and return.
token_str = input_str + 2;
input_str += 3;

4
token.h

@ -3,6 +3,8 @@
#include <stddef.h>
typedef int token_t;
#define TOK_NULL 0
#define TOK_ERR -1
#define TOK_NUMDEC 1
@ -18,7 +20,7 @@
extern const char *input_str, *token_str;
int tokenize();
token_t tokenize();
#define ISDIGIT(c) (c >= '0' && c <= '9')
#define ISHEX(c) (c & 0xDF >= 'A' && c & 0xDF <= 'F') || ISDIGIT(c)

Loading…
Cancel
Save