Created
March 7, 2013 16:52
-
-
Save yosida95/5109599 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <string.h> | |
| #include <stdlib.h> | |
| #include <math.h> | |
| #include <X11/Xlib.h> | |
| #include <X11/Xutil.h> | |
| #include <X11/Xatom.h> | |
| #include <X11/Xlocale.h> | |
| #define WINDOW_WIDTH 520 | |
| #define WINDOW_HEIGHT 520 | |
| #define PLOT_COUNT 511 | |
| struct Node{ | |
| char expression[255]; | |
| struct Node *left; | |
| struct Node *right; | |
| }; | |
| void remove_spaces(char *string){ | |
| char *source = string, | |
| *result = string; | |
| while(*source != '\0'){ | |
| if(*source == ' '){ | |
| source++; | |
| }else{ | |
| *(result++) = *(source++); | |
| } | |
| } | |
| *result = '\0'; | |
| } | |
| int remove_bracket(char *string){ | |
| int length = strlen(string); | |
| int indent = 0, | |
| i; | |
| if(string[0] == '(' && string[length - 1] == ')'){ | |
| for(i = 0; i < length - 2; ++i){ | |
| string[i] = string[i + 1]; | |
| } | |
| string[length - 2] = '\0'; | |
| return 0; | |
| }else{ | |
| for(i = 0; i < length; ++i){ | |
| switch(string[i]){ | |
| case '(': | |
| indent++; | |
| break; | |
| case ')': | |
| indent--; | |
| break; | |
| } | |
| } | |
| if(indent != 0){ | |
| printf("UNBALANCED BRUCKET\n"); | |
| return 1; | |
| } | |
| } | |
| } | |
| int get_lowest_operator(char *string){ | |
| int nest = 0, | |
| lowest_position = 0, | |
| priority = 0, | |
| i; | |
| int position = -1; | |
| for(i = 0; i < strlen(string); ++i){ | |
| switch(string[i]){ | |
| case '+': | |
| case '-': | |
| priority = 3; | |
| break; | |
| case '*': | |
| case '/': | |
| priority = 2; | |
| break; | |
| case '^': | |
| priority = 1; | |
| break; | |
| case '(': | |
| nest++; | |
| continue; | |
| case ')': | |
| nest--; | |
| continue; | |
| default: | |
| continue; | |
| } | |
| if(nest == 0 && priority >= lowest_position){ | |
| position = i; | |
| lowest_position = priority; | |
| } | |
| } | |
| return position; | |
| } | |
| void strncpy_ext(char *target, char *source, int n){ | |
| int i, | |
| got_null = 0; | |
| for(i = 0; i < n; ++i){ | |
| if(got_null == 1){ | |
| target[i] = '\0'; | |
| }else{ | |
| if(source[i] == '\0'){ | |
| got_null = 1; | |
| } | |
| target[i] = source[i]; | |
| } | |
| } | |
| if(got_null == 0){ | |
| target[n] = '\0'; | |
| } | |
| } | |
| void free_node(struct Node *node){ | |
| if(node != NULL){ | |
| free_node(node->left); | |
| free_node(node->right); | |
| free(node); | |
| } | |
| } | |
| struct Node *reserve_node(struct Node *node){ | |
| node = (struct Node *) malloc(sizeof(struct Node)); | |
| if(node == NULL){ | |
| printf("MALLOC ERROR\n"); | |
| exit(EXIT_FAILURE); | |
| } | |
| return node; | |
| } | |
| int parse(struct Node *root){ | |
| int position, length, i; | |
| struct Node *left, *right; | |
| remove_bracket(root->expression); | |
| length = strlen(root->expression); | |
| position = get_lowest_operator(root->expression); | |
| if(position < 0){ | |
| root->left = NULL; | |
| root->right = NULL; | |
| return 0; | |
| } | |
| root->left = reserve_node(left); | |
| strncpy_ext(root->left->expression, root->expression, position); | |
| parse(root->left); | |
| root->right = reserve_node(right); | |
| strncpy_ext(root->right->expression, root->expression + position + 1, | |
| length - position - 1); | |
| parse(root->right); | |
| root->expression[0] = root->expression[position]; | |
| root->expression[1] = '\0'; | |
| return 0; | |
| } | |
| float string_to_float(char *target){ | |
| int i, | |
| length = strlen(target); | |
| float result = 0.0; | |
| for(i = 0; i < length; ++i){ | |
| if(target[i] >= 0x30 && target[i] <= 0x39){ | |
| result += ((float)(unsigned char)(target[i] - '0')) * (float)pow(10, length - i - 1); | |
| }else{ | |
| printf("INVALID EXPRESSION\n"); | |
| exit(EXIT_FAILURE); | |
| } | |
| } | |
| return result; | |
| } | |
| void _exec_calc(struct Node *node, float x_value, | |
| float *result, int *stack_length){ | |
| if (node->left){ | |
| _exec_calc(node->left, x_value, result, stack_length); | |
| } | |
| if (node->right){ | |
| _exec_calc(node->right, x_value, result, stack_length); | |
| } | |
| switch(*node->expression){ | |
| case '+': | |
| result[(*stack_length) - 2] = result[(*stack_length) - 2] | |
| + result[(*stack_length) - 1]; | |
| --(*stack_length); | |
| break; | |
| case '-': | |
| result[(*stack_length) - 2] = result[(*stack_length) - 2] | |
| - result[(*stack_length) - 1]; | |
| --(*stack_length); | |
| break; | |
| case '*': | |
| result[(*stack_length) - 2] = result[(*stack_length) - 2] | |
| * result[(*stack_length) - 1]; | |
| --(*stack_length); | |
| break; | |
| case '/': | |
| result[(*stack_length) - 2] = result[(*stack_length) - 2] | |
| / result[(*stack_length) - 1]; | |
| --(*stack_length); | |
| break; | |
| case '^': | |
| result[(*stack_length) - 2] = pow( | |
| result[(*stack_length) - 2], result[(*stack_length) - 1] | |
| ); | |
| --(*stack_length); | |
| break; | |
| case 'x': | |
| result[(*stack_length)++] = x_value; | |
| break; | |
| default: | |
| result[(*stack_length)++] = string_to_float(node->expression); | |
| break; | |
| } | |
| } | |
| float exec_calc(struct Node *node, float x_value){ | |
| float result[255]; | |
| int counter = 0; | |
| _exec_calc(node, x_value, result, &counter); | |
| return result[0]; | |
| } | |
| void get_points(char *expression, XPoint *result){ | |
| struct Node *tree; | |
| float i; | |
| int j; | |
| float center_x = (float) WINDOW_WIDTH / 2, | |
| center_y = (float) WINDOW_HEIGHT / 2; | |
| float max_x_value = ((float)(PLOT_COUNT / 2)) / 10.0; | |
| float min_x_value = -1.0 * max_x_value; | |
| tree = reserve_node(tree); | |
| strcpy(tree->expression, expression); | |
| if(parse(tree) < 0){ | |
| printf("INVALID EXPRESSION\n"); | |
| exit(EXIT_FAILURE); | |
| } | |
| for(i = min_x_value, j = 0; i <= max_x_value; i += 0.1, ++j){ | |
| result[j].x = (short) center_x + (i * 10.0); | |
| // Y coordinate is reversed in XWindow | |
| result[j].y = (short) center_y - (exec_calc(tree, i) * 10.0); | |
| } | |
| free_node(tree); | |
| } | |
| void get_expression(char *expression){ | |
| printf("\ | |
| GraphRenderer\n\ | |
| \n\ | |
| * Operator Guide *\n\ | |
| add - +\n\ | |
| sub - -\n\ | |
| mul - *\n\ | |
| div - /\n\ | |
| pow - ^\n\ | |
| \n\ | |
| * ATTENTION *\n\ | |
| YOU CAN USE ONLY A DECIMAL INTEGER. IF YOU WANT TO ENTER A DECIMAL FRACTION, YOU HAVE TO ENTER IT AS A FRACTIONAL EXPRESSION WITH BRACKETS.\n\ | |
| \n"); | |
| printf("y = "); | |
| scanf("%[^\n]", expression); | |
| remove_spaces(expression); | |
| } | |
| int main(){ | |
| Display *dpy; | |
| XTextProperty win_name; | |
| Window top, quit; | |
| GC gc; | |
| XEvent event; | |
| char expression[255]; | |
| XPoint points[ PLOT_COUNT ]; | |
| get_expression(expression); | |
| get_points(expression, points); | |
| dpy = XOpenDisplay(NULL); | |
| if(dpy == NULL){ | |
| printf("Couldn't connect to XServer\n"); | |
| return 1; | |
| } | |
| top = XCreateSimpleWindow( | |
| dpy, RootWindow(dpy, 0), 0, 0, | |
| WINDOW_WIDTH, WINDOW_HEIGHT, 1, BlackPixel(dpy, 0), WhitePixel(dpy, 0) | |
| ); | |
| win_name.value = "GraphRenderer"; | |
| win_name.encoding = XA_STRING; | |
| win_name.format = 8; | |
| win_name.nitems = strlen(win_name.value); | |
| XSetWMName(dpy, top, &win_name); | |
| gc = XCreateGC(dpy, top, 0, 0); | |
| quit = XCreateSimpleWindow( | |
| dpy, top, WINDOW_WIDTH - 40 - 2 * 2 - 5, 5, | |
| 40, 20, 1, BlackPixel(dpy, 0), WhitePixel(dpy, 0) | |
| ); | |
| XMapSubwindows(dpy, top); | |
| XMapWindow(dpy, top); | |
| XFlush(dpy); | |
| XSelectInput(dpy, top, ExposureMask); | |
| XSelectInput( | |
| dpy, quit, ButtonPressMask | EnterWindowMask | LeaveWindowMask | |
| ); | |
| while(1){ | |
| XNextEvent(dpy, &event); | |
| switch(event.type){ | |
| case Expose: | |
| if(event.xexpose.count == 0){ | |
| // x-axis | |
| XDrawLine(dpy, top, gc, 0, WINDOW_HEIGHT / 2, WINDOW_WIDTH, WINDOW_HEIGHT / 2); | |
| XDrawString( | |
| dpy, top, gc, | |
| WINDOW_WIDTH - 10, WINDOW_HEIGHT / 2 - 10, "x", 1 | |
| ); | |
| // y-axis | |
| XDrawLine(dpy, top, gc, WINDOW_WIDTH / 2, 0, WINDOW_WIDTH / 2, WINDOW_HEIGHT); | |
| XDrawString( | |
| dpy, top, gc, | |
| WINDOW_WIDTH / 2- 10, 10, "y", 1 | |
| ); | |
| // plots | |
| XDrawPoints(dpy, top, gc, points, PLOT_COUNT, CoordModeOrigin); | |
| // quit button | |
| XDrawString(dpy, quit, gc, 8, 15, "Quit", 4); | |
| XFlush(dpy); | |
| } | |
| break; | |
| case ButtonPressMask: | |
| // on quit button pressed | |
| XFreeGC(dpy, gc); | |
| XDestroyWindow(dpy, quit); | |
| XDestroyWindow(dpy, top); | |
| XCloseDisplay(dpy); | |
| return 0; | |
| case EnterNotify: | |
| // quit button onmouse | |
| XSetWindowBorderWidth(dpy, quit, 2); | |
| XFlush(dpy); | |
| break; | |
| case LeaveNotify: | |
| // quit button onunmouse | |
| XSetWindowBorderWidth(dpy, quit, 1); | |
| XFlush(dpy); | |
| break; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment