PC_graph/main.c
2024-12-28 14:31:05 +01:00

116 lines
3.0 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include "lex.h"
#include "parser.h"
#include "ps_graph.h"
#include "errors.h"
static void print_usage(FILE *f, const char *name) {
fprintf(f, "Usage: %s <function> <output file> [<range>]\n", name);
fprintf(f, " <function> ..... The function to plot the graph of.\n");
fprintf(f, " <output file> .. Name of the output PostScript file.\n");
fprintf(f, " <range> ........ Ranges of the graph in the format of \"xMin:xMax:yMin:yMax\". Optional.\n");
}
static int read_double(const char **str, double *out) {
char *end;
*out = strtod(*str, &end);
if (*str == end)
return 0;
*str = end;
return 1;
}
#define EXPECT_DOUBLE(str, out) \
if (!read_double(&str, out)) \
return 0;
#define EXPECT_CHAR(str, c) \
if (*str++ != c) \
return 0;
static int parse_range(const char *str, struct graph_range *range) {
EXPECT_DOUBLE(str, &range->xmin);
EXPECT_CHAR(str, ':');
EXPECT_DOUBLE(str, &range->xmax);
EXPECT_CHAR(str, ':');
EXPECT_DOUBLE(str, &range->ymin);
EXPECT_CHAR(str, ':');
EXPECT_DOUBLE(str, &range->ymax);
EXPECT_CHAR(str, '\0');
return 1;
}
static enum error_code export_to_file(const struct expr_node *node, const struct graph_range *range, const char *function, const char *out_name) {
FILE *file;
if (!(file = fopen(out_name, "w"))) {
fprintf(stderr, "Cannot open \"%s\" for writing!\n", out_name);
return ERR_INVALID_FILENAME;
}
ps_generate_graph(file, node, range, function);
fclose(file);
return ERR_NO_ERR;
}
#ifdef ENABLE_GRAPHVIZ_EXPORT
static void export_gv(const struct expr_node *node, const char *out_name) {
FILE *file;
if (!(file = fopen(out_name, "w"))) {
fprintf(stderr, "GV: Cannot open \"%s\" for writing!\n", out_name);
return;
}
node_debug_print_gv(node, file);
fclose(file);
}
#endif /* ENABLE_GRAPHVIZ_EXPORT */
int main(int argc, char *argv[]) {
enum error_code err;
struct parser parser;
struct expr_node *node;
struct graph_range range;
if (argc < 3) {
print_usage(stderr, argv[0]);
return ERR_INVALID_ARGS;
}
if (argc > 3) {
if (!parse_range(argv[3], &range)) {
fprintf(stderr, "Invalid format of ranges! The correct format is \"xMin:xMax:yMin:yMax\".\n");
return ERR_INVALID_LIMITS;
}
}
else {
range.xmin = -10.0;
range.xmax = 10.0;
range.ymin = -10.0;
range.ymax = 10.0;
}
node = parser_parse(&parser, argv[1], "x");
if (!node) {
fprintf(stderr, "%s", parser_get_error_text(&parser));
return parser_get_error(&parser);
}
err = export_to_file(node, &range, argv[1], argv[2]);
#ifdef ENABLE_GRAPHVIZ_EXPORT
export_gv(node, "graph.dot");
#endif /* ENABLE_GRAPHVIZ_EXPORT */
node_free(node);
return err;
}