view baum.c @ 55:6279e5b14d9e

added error handling for fopen and malloc; code cleanups
author meillo@marmaro.de
date Sun, 16 Mar 2008 10:40:53 +0100
parents 6e46b106c334
children b7544f23673b 73de2151aebd
line wrap: on
line source

/*
 * baum - an esoteric programming language
 *
 * (c) markus schnalke <meillo@marmaro.de>
 * and julian forster
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "baum.h"

#define VERSION "0.4"


void printNode(struct Node* node, int level);
void printTree(struct Node* root, int level);
struct Node* lastNode(struct Node* node);
void delete(struct Node* node);


struct Stackitem {
	struct Node* node;
	struct Stackitem* next;
};



struct Node* root = 0;
struct Stackitem* stack = NULL;


void logit(char* text) {
	if (option_verbose) {
		fprintf(stderr, "[%s]\n", text);
	}
}


/* new */
struct Node* newNode(char* name, unsigned char value) {
	struct Node* node;
	node = (struct Node*) malloc(sizeof(struct Node));
	if (node == NULL) {
		perror("unable to allocate memory");
		exit(10);
	}
	strcpy(node->name, name);
	node->value = value;
	node->right = 0;
	node->down = 0;
	return node;
}



struct Node* lastNode(struct Node* node) {
	while (node->right != NULL) {
		node = node->right;
	}
	return node;
}

struct Node* insertLast(struct Node* node, struct Node* insert) {
	node = lastNode(node);
	node->right = insert;
	return insert;
}

struct Node* copyTree(struct Node* node) {
	if (node == NULL) {
		return NULL;
	}
	struct Node* tmp;
	tmp = newNode(node->name, node->value);
	tmp->down = copyTree(node->down);
	tmp->right = copyTree(node->right);
	return tmp;
}


/* delete */
void delete(struct Node* node) {
	if (node == NULL) {
		return;
	}
	delete(node->down);
	delete(node->right);
	free(node); node=0;
}


/* print */
void printNode(struct Node* node, int level) {
	if (node == NULL) {
		return;
	}
	while (level-- > 0) {
		fprintf(stderr, "\t");
	}
	fprintf(stderr, "%s (%d|%c)\n", node->name, node->value, node->value);
}

void printTree(struct Node* root, int level) {
	if (root == NULL) {
		return;
	}
	printNode(root, level);
	printTree(root->down, level+1);
	printTree(root->right, level);
}





/* stack for read_input */
void push(struct Node* node) {
	struct Stackitem* tmp;
	struct Stackitem* new;
	new = (struct Stackitem*) malloc(sizeof(struct Stackitem));
	if (new == NULL) {
		perror("unable to allocate memory");
		exit(10);
	}
	new->node = node;
	tmp = stack;
	stack = new;
	stack->next = tmp;
}
struct Node* pull() {
	if (stack == NULL) {
		return NULL;
	}
	struct Stackitem* tmp;
	struct Node* node;
	tmp = stack;
	stack = stack->next;
	node = tmp->node;
	free(tmp); tmp=0;
	return node;
}



/* read input */
void read_input(char* filename) {
	int c;
	int indent;
	char name[256];
	int value;
	int last_indent;
	struct Node* last_node;
	struct Node* node;
	FILE* file;

	indent = 0;
	strcpy(name, "");
	value = 0;
	last_indent = -1;
	last_node = NULL;
	file = fopen(filename, "r");
	if (file == NULL) {
		perror("unable to open file");
		exit(10);
	}

	while ((c = getc(file)) != EOF) {
		if (c == '#') {  /* comment */
			while ((c = getc(file)) != '\n') {
			}
		}

		if (c == ' ' || c == '\t') {  /* indent if at start of line */
			if (strlen(name) == 0) {
				indent++;
			}
		}

		if (c == '\n') {  /* end of line: create node */
			if (strlen(name) > 0) {
				/* create node */
				node = newNode((char*) name, value);
				if (indent > last_indent) { /* down */
					/* if it goes more than one level down -> error */
					if (indent > last_indent + 1) {
						fprintf(stderr, "error: Indention over more than one level. Only indent by one!\n");
						exit(5);
					}
					if (last_node == NULL) {
						root = node;
						last_node = root;
					} else {
						last_node->down = node;
					}
					push(last_node);
				} else if (indent == last_indent) { /* right */
					last_node->right = node;
				} else if (indent < last_indent) { /* up */
					/* handle if it goes more than one level up */
					while (indent < last_indent) {
						last_node = pull();
						last_indent--;
					}
					last_node->right = node;
				}
				last_indent = indent;
				last_node = node;
			}
			indent = 0;
			strcpy(name, "");
			value = 0;
		}

		if (c >= 'a' && c <= 'z') {  /* name */
			int i = 1;
			name[0] = (char) c;
			while ((c = getc(file)) != '(') {
				name[i] = (char) c;
				i++;
				if (i > 255) {
					fprintf(stderr, "error: node name too long, or no value given\n");
					exit(6);
				}
			}
			name[i] = '\0';
		}

		if (c == '(') {  /* value */
			fscanf(file, "%d)", &value);
		}

	}

	/* clear stack */
	while (stack != NULL) {
		pull();
	}

	fclose(file);
}



/* main */
int main(int argc, char* argv[]) {
	unsigned char shell_return = 0;

	option_verbose = 0;
	
	while (--argc > 0 && (*++argv)[0] == '-') {
		if (strcmp(argv[0], "--version") == 0) {
			printf("\
baum %s\n\
an esoteric programming language\n\
by markus schnalke and julian forster\n\
http://prog.marmaro.de/baum\n\
", VERSION);
			exit(0);
		} else if (strcmp(argv[0], "--help") == 0) {
			printf("\
baum --version        print version information and exit\n\
baum --help           print this output\n\
baum [-v] <file>      (verbosly) run file\n\
");
			exit(0);
		} else if (strcmp(argv[0], "-v") == 0) {
			option_verbose = 1;
			/*
		} else if (strcmp(argv[0], "-W") == 0) {
			/ * TODO: catch if no value given * /
			iDWarn = atoi((++argv)[0]);
			argc--;
			*/
		} else {
			fprintf(stderr, "unknown option: %s\n", argv[0]);
			exit(126);
		}
	}

	if (argc != 1) {
		fprintf(stderr, "%d source files given, please specify one.\n", argc);
		exit(3);
	}

	read_input(argv[0]);

	if (option_verbose) {
		fprintf(stderr, "\n\ntree read from input:\n");
		printTree(root, 1);
	}

	shell_return = action(root);
	fflush(stdout);

	if (option_verbose) {
		fprintf(stderr, "\n\nmodified tree after execution:\n");
		printTree(root, 1);
	}

	delete(root);
	exit(shell_return);
}