aboutsummaryrefslogblamecommitdiffstats
path: root/calc-example/calc.c
blob: c5f63962b8221b537eaf7289a6ae153b3a021a0f (plain) (tree)
1
2
3
4
5
6
                                                         



                   
                      






































































































                                                                  
              
 



                                                           



                                                           





                                                                                          

                                                       
                                                                                                         

                                          

                                                                   









                                             
/* See LICENSE file for copyright and license details. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libparser.h>


static void
free_input(struct libparser_unit *node)
{
	struct libparser_unit *next;
	for (; node; next = node->next, free(node), node = next)
		free_input(node->in);
}


static intmax_t
calculate(struct libparser_unit *node, const char *line)
{
	struct libparser_unit *next;
	intmax_t value = 0;
	int op;
	if (!node->rule) {
		next = node->in->next;
		value = calculate(node->in, line);
		free_input(next);
	} else if (!strcmp(node->rule, "DIGIT")) {
		value = (intmax_t)(line[node->start] - '0');
	} else if (!strcmp(node->rule, "sign")) {
		value = !strcmp(node->in->rule, "SUB") ? -1 : +1;
		free(node->in);
	} else if (!strcmp(node->rule, "unsigned")) {
		value = 0;
		next = node->in;
		free(node);
		for (node = next; node; node = next) {
			next = node->next;
			value *= 10;
			value += calculate(node, line);
		}
	} else if (!strcmp(node->rule, "number")) {
		next = node->in->next;
		value = calculate(node->in, line);
		free(node);
		for (node = next; node; node = next) {
			next = node->next;
			value *= calculate(node, line);
		}
	} else if (!strcmp(node->rule, "value")) {
		next = node->in->next;
		value = calculate(node->in, line);
		if (next)
			value *= calculate(next, line);
	} else if (!strcmp(node->rule, "hyper1")) {
		next = node->in->next;
		value = calculate(node->in, line);
		free(node);
		node = next;
		while (node) {
			next = node->next;
			op = !strcmp(node->rule, "SUB") ? -1 : +1;
			free(node);
			node = next;
			next = node->next;
			if (op < 0)
				value -= calculate(node, line);
			else
				value += calculate(node, line);
			node = next;
		}
	} else if (!strcmp(node->rule, "hyper2")) {
		next = node->in->next;
		value = calculate(node->in, line);
		free(node);
		node = next;
		while (node) {
			next = node->next;
			op = !strcmp(node->rule, "DIV") ? -1 : +1;
			free(node);
			node = next;
			next = node->next;
			if (op < 0)
				value /= calculate(node, line);
			else
				value *= calculate(node, line);
			node = next;
		}
	} else if (node->rule[0] != '@') {
		abort();
	} else if (node->in) {
		next = node->in->next;
		value = calculate(node->in, line);
		if (next)
			free_input(next);
	}
	free(node);
	return value;
}


int
main(int argc, char *argv[])
{
	struct libparser_unit *input;
	char *line = NULL;
	size_t size = 0;
	ssize_t len;
	intmax_t res;
	int r;

	if (argc == 2 ? strcmp(argv[1], "--") : argc > 2) {
		fprintf(stderr, "usage: %s\n", argv[0]);
		return 1;
	}

	while ((len = getline(&line, &size, stdin)) >= 0) {
		if (len && line[len - 1] == '\n')
			line[--len] = '\0';
		r = libparser_parse_file(libparser_rule_table, line, (size_t)len, &input);
		if (r < 0) {
			perror("libparser_parse_file");
			continue;
		} else if (!input) {
			fprintf(stderr, "didn't find anything to parse\n");
			continue;
		} else if (input->end != (size_t)len) {
			fprintf(stderr, "line could not be parsed, stopped at column %zu\n", input->end);
			free_input(input);
			continue;
		} else if (!r) {
			fprintf(stderr, "premature end of line\n");
			free_input(input);
			continue;
		}
		res = calculate(input, line);
		printf("%ji\n", res);
	}

	free(line);
	return 0;
}