From d02111da4f0cd3573c9baa518a59124f5526bb8f Mon Sep 17 00:00:00 2001 From: vitalkrilov Date: Thu, 21 Apr 2022 21:26:05 +0000 Subject: [PATCH] Graph (branch: tcc_current): - Code refactoring - Optimization of code (for example, log2(n) searching) and memory usage - Some possible memory corruption fixed - Previous graph will be erased from window if error occured - Fixed bug with provided array of non-sorted points: so now you can pass points in any order - Fixed important bug with graphic rendering (big thanks to turbocat for asm rounding function) - Changed error messages; now you can see line/byte of file where syntax error is; added checking if provided frame of graph is invalid - Autochoosing of an optimal single step for both axises - Added support for reading any number of different functions. You will have to end previous function with ';' if you want to pass another one. They will be rendered on a graph in order you passed them. git-svn-id: svn://kolibrios.org@9778 a494cfbc-eb01-0410-851d-a64ba20cac60 --- .../other/graph/branches/tcc_current/func.c | 5 + .../other/graph/branches/tcc_current/func.h | 9 +- .../other/graph/branches/tcc_current/main.c | 680 +++++++++++------- .../other/graph/branches/tcc_current/parser.c | 27 +- 4 files changed, 448 insertions(+), 273 deletions(-) diff --git a/programs/other/graph/branches/tcc_current/func.c b/programs/other/graph/branches/tcc_current/func.c index ac34fbce0d..4207d6fd58 100755 --- a/programs/other/graph/branches/tcc_current/func.c +++ b/programs/other/graph/branches/tcc_current/func.c @@ -1,4 +1,5 @@ #include "func.h" +#include // For fabs() char debuf[50] = ""; @@ -60,4 +61,8 @@ double convert(const char* s, int* len) { res += tail/div; if (len) *len=i; return sign*res; +} + +int isequal(double a, double b) { + return fabs(a-b) < EQUALITY_VAL; } \ No newline at end of file diff --git a/programs/other/graph/branches/tcc_current/func.h b/programs/other/graph/branches/tcc_current/func.h index 8a3538e607..ab1f5912df 100755 --- a/programs/other/graph/branches/tcc_current/func.h +++ b/programs/other/graph/branches/tcc_current/func.h @@ -13,8 +13,15 @@ typedef struct { double textwidth(const char* s, int len); double textheight(const char* s, int len); -typedef double (*function_t)(double); int isalpha(char c); double convert(const char* s, int* len); +static inline +int roundi(double a) { + return round(a); +} + +#define EQUALITY_VAL 0.000001 +int isequal(double a, double b); + #endif /* FUNC_H */ diff --git a/programs/other/graph/branches/tcc_current/main.c b/programs/other/graph/branches/tcc_current/main.c index 362b6e993a..6953fd780d 100755 --- a/programs/other/graph/branches/tcc_current/main.c +++ b/programs/other/graph/branches/tcc_current/main.c @@ -4,12 +4,12 @@ #include #include #include +#include #include "func.h" #include "parser.h" #define nullptr 0 -#define dword unsigned int enum BUTTONS { BTN_QUIT = 1, @@ -18,9 +18,12 @@ enum BUTTONS { const char STR_PROGRAM_TITLENAME[] = "Graph"; const char empty_text[] = "No function loaded. Type file name and press Enter. "; -const char er_file_not_found[] = "Cannot open file. "; +const char er_file_not_found[] = "Couldn't open file."; +const char er_wrong_syntax[] = "Syntax error in file: at line %d, at byte %d."; +const char er_invalid_graph_size[] = "Invalid graph size (look at passed x1,x2,y1,y2 graph's border coords)."; const char str_filename[] = "Filename:"; const char str_editfile[] = "Edit"; +const char f_str[] = ". Function y="; const char STR_ERR_CONSOLEINIT[] = "Unable to initialize console."; const char STR_MSG_HELP_USAGE[] = "Usage: %s [OPTION] [FILENAME]...\n"; const char* STR_MSG_HELP[] = { @@ -55,38 +58,51 @@ const char* STR_MSG_HELP[] = { #define FORMAT "%.2f%c" // format for two coords #define FORMAT_COORD "(%.2f, %.2f)%c" -// special value to text if enough space -#define FORMAT_TEST "0.00" - -#define DELTA_BIG 1.0 -#define DELTA_SMALL 0.1 int SysColor = 0; +double grx1, gry1, grx2, gry2; -double* points; -dword point_count = 0; -double x1, y1, x2, y2; -char* funct = nullptr; +#define FUNCTS_MAXLEN_INITIAL 1 +void** functs; // Array of addresses, first byte of struct always should describe its type +unsigned int functs_maxlen = 0; +unsigned int functs_count = 0; + +#define FUNCTS_PTYPE 0 +#define PFUNCT_POINTS_MAXLEN_INITIAL 16 +typedef struct { + char type; + double* points; + unsigned int points_maxlen; + unsigned int points_count; +} PFunct; + +#define FUNCTS_ETYPE 1 +typedef struct { + char type; + char* expr; +} EFunct; char edit_path[256]; edit_box mybox = { 200, 92, WND_H-16-32, 0xffffff, 0x94AECE, 0, 0x808080, 0x10000000, sizeof(edit_path)-1, (void*)&edit_path, 0, 0, 0 }; +int full_head_size; char* full_head; -char* HugeBuf = nullptr; +char* lasterror_text = nullptr; +int lasterror_color; // constructor of TCoord TCoord coord(double x, double y) { - TCoord r; - r.x = x; - r.y = y; - return r; + TCoord r; + r.x = x; + r.y = y; + return r; } // move and scale mathematical coords to fit screen coords TCoord mat2Graf(TCoord c, TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax) { - TCoord r; + TCoord r; if (c.x > mMax.x) c.x = mMax.x; if (c.x < mMin.x) @@ -101,65 +117,74 @@ TCoord mat2Graf(TCoord c, TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax return r; } +//just for rounding... +void DrawLine(double xs, double ys, double xe, double ye, ksys_color_t color) { + _ksys_draw_line(roundi(xs), roundi(ys), roundi(xe), roundi(ye), color); +} +void DrawText(const char* text, double x, double y, uint32_t len, ksys_color_t color) { + _ksys_draw_text(text, roundi(x), roundi(y), len, color); +} + +double delta_getoptsize(int n) { + return pow(2, n % 3) * pow(10, n / 3); +} +//Returns res: delta_getoptsize(res) <= size < delta_getoptsize(res+1) +int delta_getn(double size) { + int res = floor(log10(size) * 3); + double t = delta_getoptsize(res + 1); + if (t < size || isequal(t, size)) ++res; + return res; +} + // huge function to draw all the stuff except the function itself void drawAxis(TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax) { - TCoord cZero={0.0,0.0}, - gMin, gMax, gZero, step; + TCoord cZero = {0.0,0.0}, gMin, gMax, gZero, step; TCoord from, to; - double i=0.0; - int j; - double xmin, xmin2, ymin, ymin2; + double i = 0.0; char buf[30]=""; int strlentemp; + double deltaBigX = delta_getoptsize(delta_getn(mMax.x - mMin.x)) / 20; + double deltaBigY = delta_getoptsize(delta_getn(mMax.y - mMin.y)) / 20; + double deltaSmallX = deltaBigX / 5; + double deltaSmallY = deltaBigY / 5; // scr means Screen(bounding rect) // m means Mathematical // g means Graphic(real screen position) - //_ksys_debug_puts("draw axis called\n"); - - //sprintf(debuf, "test: %f,%f,%f,%f\n", 123.45, 1.0, -0.9, 12.57); - //_ksys_debug_puts(debuf); - gMin = mat2Graf(mMin, scrMin, scrMax, mMin, mMax); gMax = mat2Graf(mMax, scrMin, scrMax, mMin, mMax); gZero = mat2Graf(cZero, scrMin, scrMax, mMin, mMax); - // clear - // SysColor = WHITE; - //rectangle(di(gMin.x), di(gMin.y), di(gMax.x), di(gMax.y)); - // ftopku - SysColor = BLACK; - // osy X - _ksys_draw_line(gMin.x, gZero.y ,gMax.x, gZero.y, SysColor); - // osy Y - _ksys_draw_line(gZero.x, gMin.y, gZero.x, gMax.y, SysColor); - // bounding rect - _ksys_draw_line(gMin.x, gMin.y, gMax.x, gMin.y, SysColor); - _ksys_draw_line(gMin.x, gMax.y, gMax.x, gMax.y, SysColor); - _ksys_draw_line(gMin.x, gMin.y, gMin.x, gMax.y, SysColor); - _ksys_draw_line(gMax.x, gMin.y, gMax.x, gMax.y, SysColor); + DrawLine(gMin.x, gZero.y ,gMax.x, gZero.y, SysColor); // osy X + DrawLine(gZero.x, gMin.y, gZero.x, gMax.y, SysColor); // osy Y + + // bounding rect + DrawLine(gMin.x, gMin.y, gMax.x, gMin.y, SysColor); + DrawLine(gMin.x, gMax.y, gMax.x, gMax.y, SysColor); + DrawLine(gMin.x, gMin.y, gMin.x, gMax.y, SysColor); + DrawLine(gMax.x, gMin.y, gMax.x, gMax.y, SysColor); // coords of the rect : lower left - sprintf(buf, FORMAT_COORD, x1, y1, '\0'); + sprintf(buf, FORMAT_COORD, grx1, gry1, '\0'); //_ksys_debug_puts(buf); strlentemp = strlen(buf); - _ksys_draw_text(buf, gMin.x, gMin.y + textheight(buf, strlentemp), strlentemp, SysColor); + DrawText(buf, gMin.x, gMin.y + textheight(buf, strlentemp), strlentemp, SysColor); // upper left - sprintf(buf, FORMAT_COORD, x1, y2, '\0'); + sprintf(buf, FORMAT_COORD, grx1, gry2, '\0'); strlentemp = strlen(buf); - _ksys_draw_text(buf, gMin.x, gMax.y - textheight(buf, strlentemp), strlentemp, SysColor); + DrawText(buf, gMin.x, gMax.y - textheight(buf, strlentemp), strlentemp, SysColor); // lower right - sprintf(buf, FORMAT_COORD, x2, y1, '\0'); + sprintf(buf, FORMAT_COORD, grx2, gry1, '\0'); strlentemp = strlen(buf); - _ksys_draw_text(buf, gMax.x - textwidth(buf, strlentemp), gMin.y + textheight(buf, strlentemp), strlentemp, SysColor); + DrawText(buf, gMax.x - textwidth(buf, strlentemp), gMin.y + textheight(buf, strlentemp), strlentemp, SysColor); // upper right - sprintf(buf, FORMAT_COORD, x2, y2, '\0'); + sprintf(buf, FORMAT_COORD, grx2, gry2, '\0'); strlentemp = strlen(buf); - _ksys_draw_text(buf, gMax.x - textwidth(buf, strlentemp), gMax.y - textheight(buf, strlentemp), strlentemp, SysColor); + DrawText(buf, gMax.x - textwidth(buf, strlentemp), gMax.y - textheight(buf, strlentemp), strlentemp, SysColor); //_ksys_debug_puts("some lines painted\n"); @@ -167,13 +192,13 @@ void drawAxis(TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax) { step.x = (mMax.x - mMin.x) / (scrMax.x - scrMin.x); step.y = (mMax.y - mMin.y) / (scrMax.y - scrMin.y); -// round values - xmin = (int)((mMin.x / DELTA_BIG) * DELTA_BIG); - ymin = (int)((mMin.y / DELTA_BIG) * DELTA_BIG); + //roundi values + double xmin = round(mMin.x / deltaBigX) * deltaBigX; + double ymin = round(mMin.y / deltaBigY) * deltaBigY; // (0,0) - if ((x1 * x2 <= 0.0) && (y1 * y2 <= 0.0)) + if ((grx1 * grx2 <= 0.0) && (gry1 * gry2 <= 0.0)) { from.x=0.0; from.y=0.0; @@ -181,14 +206,14 @@ void drawAxis(TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax) { SysColor = BLACK; sprintf(buf, FORMAT, 0.0, '\0'); strlentemp = strlen(buf); - _ksys_draw_text(buf, from.x - textwidth(buf, strlentemp), from.y + textheight(buf, strlentemp), strlentemp, SysColor); + DrawText(buf, from.x - textwidth(buf, strlentemp), from.y + textheight(buf, strlentemp), strlentemp, SysColor); } // big marks on X //settextstyle(0, 0, 1); - if (DELTA_BIG / step.x > THREE) { - for (i = xmin; i <= mMax.x; i += DELTA_BIG) { + if (deltaBigX / step.x > THREE) { + for (i = xmin; i <= mMax.x; i += deltaBigX) { if (i != 0.0) { from.x = i; to.x = from.x; @@ -197,23 +222,22 @@ void drawAxis(TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax) { from = mat2Graf(from, scrMin, scrMax, mMin, mMax); to = mat2Graf(to, scrMin, scrMax, mMin, mMax); SysColor = BLACK; - _ksys_draw_line(from.x, from.y, to.x, to.y, SysColor); + DrawLine(from.x, from.y, to.x, to.y, SysColor); // write number sprintf(buf, FORMAT, i, '\0'); strlentemp = strlen(buf); // if it fits in the GAP, then write it - if (from.y > scrMin.y && (DELTA_BIG > (textwidth(buf, strlentemp) + 1.0) * step.x)) { + if (from.y > scrMin.y && (deltaBigX > (textwidth(buf, strlentemp) + 1.0) * step.x)) { SysColor = BIGFONTCOLOR; - _ksys_draw_text(buf, from.x - textwidth(buf, strlentemp) / 2.0, to.y - textheight(buf, strlentemp), strlentemp, SysColor); + DrawText(buf, from.x - textwidth(buf, strlentemp) / 2.0, to.y - textheight(buf, strlentemp), strlentemp, SysColor); } } } } - //_ksys_debug_puts("big marks x painted\n"); // big marks on Y - if (DELTA_BIG / step.y > THREE) { - for (i = ymin; i <= mMax.y; i += DELTA_BIG) { + if (deltaBigY / step.y > THREE) { + for (i = ymin; i <= mMax.y; i += deltaBigY) { if (i != 0.0) { from.y = i; to.y = from.y; @@ -222,23 +246,23 @@ void drawAxis(TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax) { from = mat2Graf(from, scrMin, scrMax, mMin, mMax); to = mat2Graf(to, scrMin, scrMax, mMin, mMax); SysColor = BLACK; - _ksys_draw_line(from.x, from.y, to.x, to.y, SysColor); + DrawLine(from.x, from.y, to.x, to.y, SysColor); sprintf(buf, FORMAT, i, '\0'); strlentemp = strlen(buf); - if (from.x > scrMin.x && (DELTA_BIG > textheight(buf, strlentemp) * step.y)) { + if (from.x > scrMin.x && (deltaBigY > textheight(buf, strlentemp) * step.y)) { SysColor = BIGFONTCOLOR; - _ksys_draw_text(buf, from.x + TEXT_X, to.y - textheight(buf, strlentemp) / 2.0, strlentemp, SysColor); + DrawText(buf, from.x + TEXT_X, to.y - textheight(buf, strlentemp) / 2.0, strlentemp, SysColor); } } } } - xmin2 = (int)(mMin.x / DELTA_SMALL) * DELTA_SMALL; - ymin2 = (int)(mMin.y / DELTA_SMALL) * DELTA_SMALL; + double xmin2 = round(mMin.x / deltaSmallX) * deltaSmallX; + double ymin2 = round(mMin.y / deltaSmallY) * deltaSmallY; - if (DELTA_SMALL / step.x > THREE) { - j = (int)(( - xmin + xmin2 ) / DELTA_SMALL); - for (i = xmin2; i <= mMax.x; i += DELTA_SMALL, j++) { + if (deltaSmallX / step.x > THREE) { + int j = roundi((-xmin + xmin2) / deltaSmallX); + for (i = xmin2; i <= mMax.x; i += deltaSmallX, j++) { if (j % 10 == 0) { // we need to skip every tenth mark, to avoid overwriting big marks j = 0; @@ -251,12 +275,12 @@ void drawAxis(TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax) { from = mat2Graf(from, scrMin, scrMax, mMin, mMax); to = mat2Graf(to, scrMin, scrMax, mMin, mMax); SysColor = BLACK; - _ksys_draw_line(from.x, from.y, to.x, to.y, SysColor); + DrawLine(from.x, from.y, to.x, to.y, SysColor); sprintf(buf, FORMAT, i, '\0'); strlentemp = strlen(buf); - if (from.y > scrMin.y && (DELTA_SMALL > textwidth(buf, strlentemp) * step.x)) { + if (from.y > scrMin.y && (deltaSmallX > textwidth(buf, strlentemp) * step.x)) { SysColor = SMALLFONTCOLOR; - _ksys_draw_text(buf, from.x - textwidth(buf, strlentemp) / 2.0, to.y - textheight(buf, strlentemp), strlentemp, SysColor); + DrawText(buf, from.x - textwidth(buf, strlentemp) / 2.0, to.y - textheight(buf, strlentemp), strlentemp, SysColor); } @@ -265,10 +289,10 @@ void drawAxis(TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax) { } // finally small marks on Y - if (DELTA_SMALL / step.y > THREE) { + if (deltaSmallY / step.y > THREE) { //_ksys_debug_puts("really small marks y painted\n"); - j = (int)(( - ymin + ymin2) / DELTA_SMALL); - for (i = ymin2; i <= mMax.y; i += DELTA_SMALL, j++) { + int j = roundi((-ymin + ymin2) / deltaSmallY); + for (i = ymin2; i <= mMax.y; i += deltaSmallY, j++) { if (j % 10 == 0) { // we need to skip every tenth, to avoid overwriting j = 0; @@ -281,198 +305,318 @@ void drawAxis(TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax) { from = mat2Graf(from, scrMin, scrMax, mMin, mMax); to = mat2Graf(to, scrMin, scrMax, mMin, mMax); SysColor = BLACK; - _ksys_draw_line(from.x, from.y, to.x, to.y, SysColor); + DrawLine(from.x, from.y, to.x, to.y, SysColor); sprintf(buf, FORMAT, i, '\0'); strlentemp = strlen(buf); - if (from.x > scrMin.x && (DELTA_SMALL > textheight(buf, strlentemp) * step.y)) { + if (from.x > scrMin.x && (deltaSmallY > textheight(buf, strlentemp) * step.y)) { SysColor = SMALLFONTCOLOR; - _ksys_draw_text(buf, from.x + TEXT_X, from.y - textheight(buf, strlentemp) / 2.0, strlentemp, SysColor); + DrawText(buf, from.x + TEXT_X, from.y - textheight(buf, strlentemp) / 2.0, strlentemp, SysColor); } } } } -/* - ends fucking piece of shit -*/ - -void drawFunction( function_t fi, TCoord scrMin, TCoord scrMax, - TCoord mMin, TCoord mMax, int color) { - double x; - double y; - int firstPoint = 1; - TCoord p, p0 = {0.0, 0.0}, step; - - drawAxis(scrMin, scrMax, mMin, mMax); - - SysColor = color; - step.x = (mMax.x - mMin.x) / (scrMax.x - scrMin.x); - - for (x = mMin.x; x < mMax.x; x += step.x) { - y = fi(x); -// function is defined here and gets in the range - if (1) { // тут было условие, что функция правильно вычислена - if ((y > mMin.y) && (y < mMax.y)) { - p = mat2Graf(coord(x, y), scrMin, scrMax, mMin, mMax); - // if it's our first point, only remember its coords - // otherwise, draw a line from prev to current - if (firstPoint == 0) { - _ksys_draw_line(p0.x, p0.y, p.x, p.y, SysColor); - } else firstPoint = 0; - p0 = p; - } - else {// too big/small - firstPoint = 1; - } - } - else { // no value - firstPoint = 1; - } - } - +// returns idx: a[idx] <= x element; -1 can be returned +int binsearchRB_xInPoints(double* a, int a_size, double x) { + int L = -1; + int R = a_size; + while (R - L > 1) { + int M = (R + L) / 2; + if (a[2*M] <= x) // 2*M because in points array there are 2 coords: x and y + L = M; + else + R = M; + } + return L; } -// итоговая версия читалки текстовых файлов -int load_points3() { - ksys_bdfe_t bdfe; - int filePointer = 0; +int calcFunct_idx; - int i,j,k; - double d; - dword filesize, num_number; - - double* p2=0; - - // get file size - int rr = _ksys_file_get_info(edit_path, &bdfe); - sprintf(debuf, "getsize: %d\n", rr); - _ksys_debug_puts(debuf); - if (rr != 0) { - _ksys_draw_text((char*)er_file_not_found, 10, 10, strlen(er_file_not_found), 0x90FF0000); +int calcFunct(double x, double* res) { + if (*(char*)functs[calcFunct_idx] == FUNCTS_ETYPE) { + set_exp(((EFunct*)functs[calcFunct_idx])->expr, x); + get_exp(res); // парсить для каждого значения х? да я с ума сошел. return 0; } - filesize = bdfe.size; - num_number = filesize / 2; + PFunct* pf = functs[calcFunct_idx]; - HugeBuf = (char*)malloc(filesize + 1); // разбираем как строку, отсюда терминатор \0 - - for (i=0;ipoints[0]) { + return 1; // Or it better return something?? + //*res = pf->points[1]; + } + if (x >= pf->points[(pf->points_count - 1) * 2]) { + return 1; // Or it better return something?? + //*res = pf->points[(pf->points_count - 1) * 2 + 1]; } -// sprintf(debuf, "(%f,%f)-(%f,%f)",x1,y1,x2,y2); -// _ksys_debug_puts(debuf); - point_count=(k - 4)/2; - // - points = (double*)malloc(point_count * 2 * 8); - for (i = 0; i < point_count * 2; i++) - points[i] = p2[i]; - free(p2); -// sprintf(debuf, "count: %d\n", point_count); -// _ksys_debug_puts(debuf); - sprintf(debuf, ". Number of points: %u.", point_count); - strcpy(full_head+strlen(full_head), debuf); - free(HugeBuf); - HugeBuf = NULL; + int i = binsearchRB_xInPoints(pf->points, pf->points_count, x); + *res = (x - pf->points[2 * i]) / (pf->points[2 * (i + 1)] - pf->points[2 * i]) + * (pf->points[2 * (i + 1) + 1] - pf->points[2 * i + 1]) + pf->points[2 * i + 1]; + return 0; +} + +void drawFunction(TCoord scrMin, TCoord scrMax, TCoord mMin, TCoord mMax, int color) { + SysColor = color; + TCoord p, p0 = {0.0, 0.0}, step; + step.x = (mMax.x - mMin.x) / (scrMax.x - scrMin.x); + int firstPoint = 1; + double y; + for (double x = mMin.x; x < mMax.x; x += step.x) { // function is defined here and gets in the range + if (!calcFunct(x, &y)) { // условие, что функция правильно вычислена + if (y > mMin.y && y < mMax.y) { + p = mat2Graf(coord(x, y), scrMin, scrMax, mMin, mMax); + // if it's our first point, only remember its coords + // otherwise, draw a line from prev to current + if (firstPoint == 0) { + DrawLine(p0.x, p0.y, p.x, p.y, SysColor); + } else firstPoint = 0; + p0 = p; + } else {// too big/small + firstPoint = 1; + } + } else { // no value + firstPoint = 1; + } + } +} + +int pointsCompare(const void* a, const void* b) { + const double aval = *(const double*)a; // first element of a + const double bval = *(const double*)b; // first element of b + if (isequal(aval, bval)) return 0; + if (aval < bval) return -1; return 1; } -// вычислить заданную функцию или кусочно-линейную между точками -double fu(double x) { - int i; - double res; - - if (funct) { - set_exp(funct,x); - get_exp(&res); // парсить для каждого значения х? да я с ума сошел. - return res; +void freeMemoryForGraphs() { + if (functs_count) { + for (int i = 0; i < functs_count; ++i) { + switch (*(char*)functs[i]) { + case FUNCTS_PTYPE: + free(((PFunct*)functs[i])->points); + break; + case FUNCTS_ETYPE: + free(((EFunct*)functs[i])->expr); + break; + } + free(functs[i]); + } + free(functs); + functs = nullptr; + functs_maxlen = 0; + functs_count = 0; } - - if (point_count == 0) { - return 0.0; - } - - if (x <= points[0]) - return points[1]; - if (x >= points[(point_count-1) * 2]) - return points[(point_count-1) * 2 + 1]; - - for (i = 0; i < point_count; i++) { - if ((x >= points[2 * i]) && (x < points[2 * (i + 1)])) - break; - } - - return (x - points[2 * i]) / (points[2 * (i + 1)] - points[2 * i]) - * (points[2 * (i + 1) + 1] - points[2 * i + 1]) + points[2 * i + 1]; - } -void draw_window(void) { - double xx0=0.0, yy0=0.0; +void functsSizeChecker() { + if (functs_maxlen <= functs_count + 1) { + if (!functs_maxlen) { + functs_maxlen = FUNCTS_MAXLEN_INITIAL; + functs = (void**)malloc(sizeof(void*) * functs_maxlen); + } else { + functs_maxlen *= 2; + functs = (void**)realloc(functs, sizeof(void*) * functs_maxlen); + } + if (!functs) exit(3); + } +} +// итоговая версия читалки текстовых файлов +// NOTICE for devs: full_head must be resetted after fail of this function (on 0 ret. code) +int load_points3() { + freeMemoryForGraphs(); + + // get file size + ksys_bdfe_t bdfe; + int rr = _ksys_file_get_info(edit_path, &bdfe); + if (rr) { + if (lasterror_text) free(lasterror_text); + lasterror_text = (char*)malloc(sizeof(er_file_not_found)); + if (!lasterror_text) exit(3); + strcpy(lasterror_text, er_file_not_found); + lasterror_color = 0x90000000; + return 0; + } + unsigned int filesize = bdfe.size; + + char* HugeBuf = (char*)malloc(filesize + 1); // разбираем как строку, отсюда терминатор '\0' + if (!HugeBuf) exit(3); + unsigned int countRead; + rr = _ksys_file_read_file(edit_path, 0, filesize, HugeBuf, &countRead); + if (countRead != filesize) exit(4); // in case if something corrupted + HugeBuf[filesize] = '\0'; + + int lineNum = 1; + int lineStartIdx = 0; + int borderNextCoord = 0; + int funct_status = 0; // 0 - empty, 1 - points (can be filled), 2 - expr. (definitely finished) + int i = 0; + while (i < filesize) { + if (isalpha(HugeBuf[i])) { + if (HugeBuf[i] == '\n') { + ++lineNum; + lineStartIdx = i + 1; + } + ++i; + continue; + } + + if (HugeBuf[i] == ';') { + if (funct_status) { + ++functs_count; + funct_status = 0; + } + ++i; + continue; + } + + if (borderNextCoord == 4 && HugeBuf[i] == '=' && !funct_status) { + functsSizeChecker(); + funct_status = 2; + functs[functs_count] = malloc(sizeof(EFunct)); + if (!functs[functs_count]) exit(3); + *(char*)functs[functs_count] = FUNCTS_ETYPE; + + EFunct* ef = functs[functs_count]; + int efunct_len; + for (efunct_len = 0; HugeBuf[i + 1 + efunct_len] != ';' && HugeBuf[i + 1 + efunct_len] != '\0'; ++efunct_len) {} + ef->expr = (char*)malloc(efunct_len+1); + if (!ef->expr) exit(3); + strncpy(ef->expr, HugeBuf + i + 1, efunct_len); + ef->expr[efunct_len] = '\0'; + i += efunct_len + 1; + continue; + } + + int j; + double d = convert(HugeBuf + i, &j); + if (d == ERROR) { + sprintf(debuf, er_wrong_syntax, lineNum, i-lineStartIdx+1); + if (lasterror_text) free(lasterror_text); + lasterror_text = (char*)malloc(strlen(debuf)+1); + if (!lasterror_text) exit(3); + strcpy(lasterror_text, debuf); + lasterror_color = 0x90FF0000; + free(HugeBuf); + freeMemoryForGraphs(); + return 0; + } + if (d == ERROR_END) { + _ksys_debug_puts("["); + _ksys_debug_puts(STR_PROGRAM_TITLENAME); + _ksys_debug_puts("] EOF reached.\n"); + break; + } + i += j; + + if (borderNextCoord < 4) { + switch (borderNextCoord) { + case 0: + grx1 = d; + break; + case 1: + grx2 = d; + break; + case 2: + gry1 = d; + break; + case 3: + gry2 = d; + if (grx1 > grx2 || isequal(grx1, grx2) || gry1 > gry2 || isequal(gry1, gry2)) { + if (lasterror_text) free(lasterror_text); + lasterror_text = (char*)malloc(sizeof(er_invalid_graph_size)); + if (!lasterror_text) exit(3); + strcpy(lasterror_text, er_invalid_graph_size); + lasterror_color = 0x90FF0000; + free(HugeBuf); + return 0; + } + break; + } + ++borderNextCoord; + } else { + if (!funct_status) { + functsSizeChecker(); + funct_status = 1; + functs[functs_count] = malloc(sizeof(PFunct)); + if (!functs[functs_count]) exit(3); + *(char*)functs[functs_count] = FUNCTS_PTYPE; + ((PFunct*)functs[functs_count])->points = nullptr; + ((PFunct*)functs[functs_count])->points_maxlen = 0; + ((PFunct*)functs[functs_count])->points_count = 0; + } + + PFunct* pf = functs[functs_count]; + if (pf->points_maxlen <= pf->points_count + 1) { + if (!pf->points_maxlen) { + pf->points_maxlen = PFUNCT_POINTS_MAXLEN_INITIAL; + pf->points = (double*)malloc(sizeof(double) * pf->points_maxlen); + } else { + pf->points_maxlen *= 2; + pf->points = (double*)realloc(pf->points, sizeof(double) * pf->points_maxlen); + } + if (!pf->points) exit(3); + } + pf->points[pf->points_count++] = d; + } + } + free(HugeBuf); + if (funct_status) ++functs_count; + + for (int f_idx = 0; f_idx < functs_count; ++f_idx) { + if (*(char*)functs[f_idx] != FUNCTS_PTYPE) continue; + PFunct* pf = functs[f_idx]; + pf->points_count /= 2; + qsort(pf->points, pf->points_count, sizeof(double)*2, pointsCompare); + } + + int full_head_new_size = sizeof(STR_PROGRAM_TITLENAME)-1 + 3 + strlen(edit_path) + 1; // 3 = strlen(" - ") + if (functs_count == 1) { + if (*(char*)functs[0] == FUNCTS_PTYPE) { + sprintf(debuf, ". Number of points: %u.", ((PFunct*)functs[0])->points_count); + full_head_new_size += strlen(debuf); + } else + full_head_new_size += sizeof(f_str)-1 + strlen(((EFunct*)functs[0])->expr); + } else { + sprintf(debuf, ". Functions loaded: %u.", functs_count); + full_head_new_size += strlen(debuf); + } + + if (full_head_new_size > full_head_size) { + free(full_head); + full_head_size = full_head_new_size; + full_head = (char*)malloc(full_head_size); + if (!full_head) exit(3); + } + char* full_head_addr = full_head; + strcpy(full_head_addr, STR_PROGRAM_TITLENAME); + full_head_addr += sizeof(STR_PROGRAM_TITLENAME)-1; + strcpy(full_head_addr, " - "); + full_head_addr += 3; // 3 = strlen(" - ") + strcpy(full_head_addr, edit_path); + full_head_addr += strlen(edit_path); + if (functs_count == 1) { + if (*(char*)functs[0] == FUNCTS_PTYPE) + strcpy(full_head_addr, debuf); + else { + strcpy(full_head_addr, f_str); + full_head_addr += sizeof(f_str)-1; + strcpy(full_head_addr, ((EFunct*)functs[0])->expr); + } + } else { + strcpy(full_head_addr, debuf); + } + + if (lasterror_text) { + free(lasterror_text); + lasterror_text = nullptr; + } + return 1; +} + +void draw_window() { _ksys_start_draw(); _ksys_create_window(100, 80, WND_W, WND_H, full_head, 0xFFFFFF, 0x33); _ksys_end_draw(); @@ -485,12 +629,18 @@ void draw_window(void) { mybox.top = cHeight - 50; mybox.width = cWidth - mybox.left - 80; - if (info.window_state&0x04) return; //draw nothing if window is rolled-up + if (info.window_state & 0x04) return; //draw nothing if window is rolled-up - if (point_count == 0 && funct == NULL) { - _ksys_draw_text((char *)empty_text, (cWidth - 8 * strlen(empty_text))/2,cHeight/2-25, strlen(empty_text), 0x90000000); + if (!functs_count) { + _ksys_draw_text(empty_text, (cWidth - 8 * strlen(empty_text)) / 2, cHeight / 2 - 25, sizeof(empty_text)-1, 0x90000000); } else { - drawFunction(&fu, coord(10, 20), coord(cWidth - 20, cHeight - 70), coord(x1,y1), coord(x2,y2), 0x00ff0000); + TCoord scrMin = coord(10, 20), + scrMax = coord(cWidth - 20, cHeight - 70), + mMin = coord(grx1, gry1), + mMax = coord(grx2, gry2); + drawAxis(scrMin, scrMax, mMin, mMax); + for (calcFunct_idx = 0; calcFunct_idx < functs_count; ++calcFunct_idx) + drawFunction(scrMin, scrMax, mMin, mMax, 0x00ff0000); } _ksys_draw_text((char*)str_filename, 15, mybox.top + 4, strlen(str_filename), 0x90000000); @@ -499,6 +649,11 @@ void draw_window(void) { _ksys_define_button(cWidth - 70, mybox.top, 50, 21, BTN_EDIT, 0xc0c0c0); _ksys_draw_text((char*)str_editfile, cWidth - 60, mybox.top + 4, 0, 0x90000000); + + if (lasterror_text) { + _ksys_draw_bar(10, 10, 200, 20, 0xFFFFFF); // фон для сообщений об ошибках + _ksys_draw_text(lasterror_text, 10, 10, strlen(lasterror_text), lasterror_color); + } } void consoleInit() { @@ -518,7 +673,9 @@ void consoleExit() { } int main(int argc, char** argv) { - full_head = (char*)malloc(300); + full_head_size = sizeof(STR_PROGRAM_TITLENAME); // also with '\0' + full_head = (char*)malloc(full_head_size); + if (!full_head) return 3; strcpy(full_head, STR_PROGRAM_TITLENAME); if (argc == 2) { @@ -530,8 +687,8 @@ int main(int argc, char** argv) { return 0; } else { strcpy(edit_path, argv[1]); - if (load_points3()) - draw_window(); + mybox.size = mybox.pos = strlen(edit_path); + load_points3(); } } else if (argc > 2) { consoleInit(); @@ -552,25 +709,12 @@ int main(int argc, char** argv) { case KSYS_EVENT_KEY: { ksys_oskey_t kc = _ksys_get_key(); switch (kc.code) { - case 0x0D: - if (HugeBuf) { - //sprintf(debuf, "freemem: HugeBuf = %X", HugeBuf); - //_ksys_debug_puts(debuf); - free(HugeBuf); // что за баг - понять не могу. - HugeBuf = nullptr; - funct = nullptr; - } - if (points) { - //sprintf(debuf, "freemem: points = %X", points); - //_ksys_debug_puts(debuf); - free(points); // и тут. ну не обращаюсь я к этому указателю, только память в него, потом снова выделяю - points = nullptr; - } - point_count = 0; - _ksys_draw_bar(10, 10, 200, 20, 0xFFFFFF); // фон для сообщений об ошибках - if (load_points3()) - draw_window(); + case 0x0D: { + int res = load_points3(); + if (!res) strcpy(full_head, STR_PROGRAM_TITLENAME); + draw_window(); break; + } default: edit_box_key_safe(&mybox, kc); } diff --git a/programs/other/graph/branches/tcc_current/parser.c b/programs/other/graph/branches/tcc_current/parser.c index 279a6ac63c..a4cf7ec0cb 100755 --- a/programs/other/graph/branches/tcc_current/parser.c +++ b/programs/other/graph/branches/tcc_current/parser.c @@ -1,6 +1,8 @@ #include #include +#include + #include "func.h" #include "parser.h" @@ -15,7 +17,7 @@ // error codes #define ERR_BADFUNCTION -1 -#define ERR_BADNUMER -2 +#define ERR_BADNUMBER -2 #define ERR_GENERAL -3 #define ERR_NOBRACKET -4 #define ERR_BADVARIABLE -5 @@ -84,11 +86,11 @@ double cosec(double d) { } double log2_p(double d) { - return log(d) / log(2); + return log2(d); } double log10_p(double d) { - return log(d) / log(10); + return log10(d); } double log3(double d) { @@ -167,6 +169,23 @@ int iswhite(char c) { } void serror(int code) { + /*switch (code) { + case ERR_BADFUNCTION: + _ksys_debug_puts("ERR_BADFUNCTION\n"); + break; + case ERR_BADNUMBER: + _ksys_debug_puts("ERR_BADNUMBER\n"); + break; + case ERR_NOBRACKET: + _ksys_debug_puts("ERR_NOBRACKET\n"); + break; + case ERR_BADVARIABLE: + _ksys_debug_puts("ERR_BADVARIABLE\n"); + break; + case ERR_OVERFLOW: + _ksys_debug_puts("ERR_OVERFLOW\n"); + break; + }*/ //TODO (vitalkrilov): for what?: "::code = code;" // longjmp(j, code); } @@ -339,7 +358,7 @@ void primitive(double* hold) { //if (sscanf(token, "%lf", hold) != 1) *hold = convert(token, nullptr); if (*hold == ERROR) - serror( ERR_BADNUMER); + serror( ERR_BADNUMBER); get_token(); return; case FUNCTION: