Guest User

Untitled

a guest
Jun 22nd, 2018
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 30.13 KB | None | 0 0
  1. /*
  2.  
  3. Invariance
  4. Version 1.0.0
  5. 2009 Stephan Boyer
  6.  
  7. */
  8.  
  9. #include "../res/resource.h"
  10. #include "ocelot.h"
  11. #include <gl/gl.h>
  12. #include "calc.h"
  13. #include "global.h"
  14. #include "errors.h"
  15. #include <vector>
  16.  
  17. using namespace std;
  18.  
  19. void make_graphs(bool silent);
  20.  
  21. bool var_exists(std::string name)
  22. {
  23. for (int i = 0; i < int(get_var_stack()->size()); i++)
  24. {
  25. if (get_var_stack()->at(i).name == name)
  26. return true;
  27. }
  28. return false;
  29. }
  30.  
  31. num get_var(std::string name)
  32. {
  33. for (int i = int(get_var_stack()->size())-1; i >= 0; i--)
  34. {
  35. if (get_var_stack()->at(i).name == name)
  36. return get_var_stack()->at(i).x;
  37. }
  38. throw_error("unknown variable '"+name+"'", true);
  39. num x;
  40. return x;
  41. }
  42.  
  43. void set_var(std::string name, float val)
  44. {
  45. var v;
  46. v.name = name;
  47. v.x = num::float_to_num(val);
  48. get_var_stack()->push_back(v);
  49. make_graphs(true);
  50. }
  51.  
  52. void set_var(std::string name, num val)
  53. {
  54. var v;
  55. v.name = name;
  56. v.x = val;
  57. get_var_stack()->push_back(v);
  58. make_graphs(true);
  59. }
  60.  
  61. struct graph_layer
  62. {
  63. node graph_node;
  64. string graph_var;
  65. };
  66.  
  67. vector <graph_layer> graph_list;
  68.  
  69. struct point
  70. {
  71. float x, y;
  72. };
  73.  
  74. vector <point> point_list;
  75.  
  76. // main window
  77. bool wnd_open;
  78. window* wnd;
  79.  
  80. void reset()
  81. {
  82. // initialize the calculating engine
  83. graph_list.clear();
  84. point_list.clear();
  85. get_var_stack()->clear();
  86. get_func_stack()->clear();
  87. (*get_angle_mode()) = ANGLE_RADIANS;
  88. // create the variables
  89. var c;
  90. c.name = "pi";
  91. c.x = num::string_to_num("3.1415926535897932384626433832795");
  92. get_var_stack()->push_back(c);
  93. c.name = "e";
  94. c.x = num::string_to_num("2.7182818284590452353602874713527");
  95. get_var_stack()->push_back(c);
  96. c.name = "xmin";
  97. c.x = num::string_to_num("-10");
  98. get_var_stack()->push_back(c);
  99. c.name = "xmax";
  100. c.x = num::string_to_num("10");
  101. get_var_stack()->push_back(c);
  102. c.name = "ymin";
  103. c.x = num::string_to_num("-10");
  104. get_var_stack()->push_back(c);
  105. c.name = "ymax";
  106. c.x = num::string_to_num("10");
  107. get_var_stack()->push_back(c);
  108. c.name = "gprec";
  109. c.x = num::string_to_num("0.1");
  110. get_var_stack()->push_back(c);
  111. c.name = "cprec";
  112. c.x = num::string_to_num("0.001");
  113. get_var_stack()->push_back(c);
  114. // redraw the window
  115. make_graphs(true);
  116. }
  117.  
  118. // about window
  119. bool wnd_about_open;
  120. window* wnd_about;
  121.  
  122. // controls
  123. int close_about;
  124.  
  125. // the message handler for the about box
  126. void msg_proc_about(message* msg)
  127. {
  128. if (msg->msg == MSG_CREATE)
  129. {
  130. // create the about graphic
  131. wnd_about->create_ctrl(CTRL_BITMAP_RESOURCE, "101", 0, 0, 400, 275);
  132. // create the close button
  133. close_about = wnd_about->create_ctrl(CTRL_BUTTON, "Close", 152, 283, 96, 24);
  134. // make the window visible
  135. wnd_about->set_window_visible(true);
  136. }
  137. if (msg->msg == MSG_BUTTONPRESSED && msg->ctrl_id == close_about)
  138. wnd_about_open = false;
  139. if (msg->msg == MSG_KEYDOWN)
  140. {
  141. if (msg->ctrl_id == OKC_ESCAPE)
  142. wnd_about_open = false;
  143. if (msg->ctrl_id == OKC_SPACE)
  144. wnd_about_open = false;
  145. if (msg->ctrl_id == OKC_RETURN)
  146. wnd_about_open = false;
  147. }
  148. if (msg->msg == MSG_CLOSE)
  149. wnd_about_open = false;
  150. }
  151.  
  152. void show_about()
  153. {
  154. // create the window and run the message loop
  155. wnd_about_open = true;
  156. wnd_about = new window("About Invariance", IDI_ICON1, 400, 315, wnd, &msg_proc_about);
  157. while (wnd_about_open) wnd_about->update();
  158. delete wnd_about;
  159. }
  160.  
  161. // reference window
  162. bool wnd_ref_open;
  163. window* wnd_ref;
  164.  
  165. // controls
  166. int info_ref;
  167. int close_ref;
  168.  
  169. // the message handler for the reference box
  170. void msg_proc_ref(message* msg)
  171. {
  172. if (msg->msg == MSG_CREATE)
  173. {
  174. // create the reference information
  175. info_ref = wnd_ref->create_ctrl(CTRL_MULTI_EDIT_READONLY,
  176. "------- Quick User's Guide -------\r\n"
  177. "\r\n"
  178. "Simple algebra: 3^5+2sqrt(2pi-1)*e/10.5\r\n"
  179. "Trig functions: sin(x), cos(x), etc...\r\n"
  180. "Custom variables: a = 5\r\n"
  181. "Custom functions: f(x, y) = 3x+5y\r\n"
  182. "Graphing: y = 8log(x)\r\n"
  183. "Graphing inverses: x = 4y\r\n"
  184. "Zoom in/out: zin and zout\r\n"
  185. "Derivatives: der sin(x), x, 1\r\n"
  186. " (function, variable of differentiation, point)\r\n"
  187. "Integrals: int 3x^4, x, 0, 4\r\n"
  188. " (function, variable of integration, lower limit, upper limit)\r\n"
  189. "\r\n"
  190. "------- Reference -------\r\n"
  191. "\r\n"
  192. "Expression Axioms:\r\n"
  193. "\r\n"
  194. "x - literal value\r\n"
  195. "x - variable\r\n"
  196. "f(x, y, z) - function call\r\n"
  197. "(x) - grouping\r\n"
  198. "x! - factorial (gamma(x+1))\r\n"
  199. "x^y - exponent (from left to right)\r\n"
  200. "x*y, x/y - multiplication/division (from left to right)\r\n"
  201. "+x, -x - positive/negative\r\n"
  202. "x+y, x-y - addition/subtraction (from left to right)\r\n"
  203. "\r\n"
  204. "Commands:\r\n"
  205. "\r\n"
  206. "deg - switch to degree mode\r\n"
  207. "rad - switch to radian mode\r\n"
  208. "grad - switch to grad mode\r\n"
  209. "reset - reset variables to default values\r\n"
  210. "clear - clear the output window\r\n"
  211. "wipe - clear the graph window\r\n"
  212. "exit - quit the program\r\n"
  213. "x = a - define a variable\r\n"
  214. "f(x, y, z) = a - define a function\r\n"
  215. "del x - delete a variable\r\n"
  216. "del x() - delete a function\r\n"
  217. "zin - zoom in\r\n"
  218. "zout - zoom out\r\n"
  219. "y = f(x), x = f(y) - graph a function\r\n"
  220. "der f(x), x, a - evaluate the derivative at a point\r\n"
  221. "int f(x), x, a, b - evaluate the definite integral\r\n"
  222. "\r\n"
  223. "Intrinsic Variables:\r\n"
  224. "\r\n"
  225. "xmin - the lower x boundry for graphing\r\n"
  226. "xmax - the upper x boundry for graphing\r\n"
  227. "ymin - the lower y boundry for graphing\r\n"
  228. "ymax - the upper y boundry for graphing\r\n"
  229. "gprec - the step size for graphing\r\n"
  230. "cprec - the limit value for calculus operations\r\n"
  231. "e - roughly equal to 2.71828...\r\n"
  232. "pi - roughly equal to 3.14159...\r\n"
  233. "\r\n"
  234. "Intrinsic Functions:\r\n"
  235. "\r\n"
  236. "abs(x) - absolute value\r\n"
  237. "acos(x) - arccosine\r\n"
  238. "asin(x) - arcsine\r\n"
  239. "atan(x) - arctangent\r\n"
  240. "cos(x) - cosine\r\n"
  241. "cot(x) - cotangent\r\n"
  242. "csc(x) - cosecant\r\n"
  243. "ln(x) - natural logarithm\r\n"
  244. "log(x) - base-10 logarithm\r\n"
  245. "sec(x) - secant\r\n"
  246. "sin(x) - sine\r\n"
  247. "sqrt(x) - square root\r\n"
  248. "tan(x) - tangent\r\n"
  249. , 8, 8, 384, 334);
  250. // create the close button
  251. close_ref = wnd_ref->create_ctrl(CTRL_BUTTON, "Close", 152, 358, 96, 24);
  252. // reposition the window
  253. wnd_ref->set_client_size(400, 400);
  254. wnd_ref->center_window();
  255. // make the window visible
  256. wnd_ref->set_window_visible(true);
  257. }
  258. if (msg->msg == MSG_RESIZED)
  259. {
  260. // get the width and height of the client area
  261. int width = wnd_ref->get_client_width();
  262. int height = wnd_ref->get_client_height();
  263. // reposition the controls
  264. wnd_ref->set_ctrl_pos(close_ref, (width-96)/2, height-32);
  265. wnd_ref->set_ctrl_size(info_ref, width-16, height-48);
  266. }
  267. if (msg->msg == MSG_BUTTONPRESSED && msg->ctrl_id == close_ref)
  268. wnd_ref_open = false;
  269. if (msg->msg == MSG_KEYDOWN)
  270. {
  271. if (msg->ctrl_id == OKC_ESCAPE)
  272. wnd_ref_open = false;
  273. if (msg->ctrl_id == OKC_SPACE)
  274. wnd_ref_open = false;
  275. if (msg->ctrl_id == OKC_RETURN)
  276. wnd_ref_open = false;
  277. }
  278. if (msg->msg == MSG_CLOSE)
  279. wnd_ref_open = false;
  280. }
  281.  
  282. void show_ref()
  283. {
  284. // create the window and run the message loop
  285. wnd_ref_open = true;
  286. wnd_ref = new window("Invariance Reference", IDI_ICON1, 0, 0, wnd, &msg_proc_ref);
  287. while (wnd_ref_open) wnd_ref->update();
  288. delete wnd_ref;
  289. }
  290.  
  291. // fonts
  292. HFONT font;
  293.  
  294. // hotkeys
  295. int hot_f1;
  296.  
  297. // controls
  298. int input;
  299. int output;
  300. int graph;
  301.  
  302. // menu items
  303. int menu_file_exit;
  304. int menu_help_ref;
  305. int menu_help_about;
  306.  
  307. // the log text
  308. string log_text;
  309. const int log_max_size = 1000;
  310.  
  311. void log(string str)
  312. {
  313. if (log_text == "")
  314. log_text = str;
  315. else
  316. log_text = str+"\r\n"+log_text;
  317. if (log_text.size() > log_max_size)
  318. log_text = log_text.substr(0, log_max_size);
  319. wnd->set_ctrl_text(output, log_text);
  320. }
  321.  
  322. void clear_log()
  323. {
  324. log_text = "";
  325. wnd->set_ctrl_text(output, log_text);
  326. }
  327.  
  328. void make_graphs(bool silent)
  329. {
  330. // ignore nonfatal errors during graphing
  331. respond_to_nonfatals(false);
  332. point_list.clear();
  333. try
  334. {
  335. // fetch the variables
  336. float xmin = num::num_to_float(get_var("xmin"));
  337. float ymin = num::num_to_float(get_var("ymin"));
  338. float xmax = num::num_to_float(get_var("xmax"));
  339. float ymax = num::num_to_float(get_var("ymax"));
  340. float prec = num::num_to_float(get_var("gprec"));
  341. if (num::num_eq(get_var("xmin"), get_var("xmax")))
  342. throw_error("xmax cannot equal xmin", true);
  343. if (num::num_eq(get_var("ymin"), get_var("ymax")))
  344. throw_error("ymax cannot equal ymin", true);
  345. if (prec <= 0.0f)
  346. throw_error("invalid value for gprec", true);
  347. for (int i = 0; i < int(graph_list.size()); i++)
  348. {
  349. try
  350. {
  351. // create the independent variable
  352. if (graph_list[i].graph_var == "x")
  353. {
  354. // the independent variable is y
  355. var v;
  356. v.name = "y";
  357. get_var_stack()->push_back(v);
  358. }
  359. else
  360. {
  361. // the independent variable is x
  362. var v;
  363. v.name = "x";
  364. get_var_stack()->push_back(v);
  365. }
  366. // graph
  367. if (graph_list[i].graph_var == "x")
  368. {
  369. point p;
  370. point p2;
  371. point p3; // used for distance checking
  372. bool first = true;
  373. if (ymin < ymax)
  374. {
  375. for (p.y = ymin-prec; p.y <= ymax+prec; p.y += prec)
  376. {
  377. get_var_stack()->at(get_var_stack()->size()-1).x = num::float_to_num(p.y);
  378. p.x = num::num_to_float(graph_list[i].graph_node.eval());
  379. // transform to screen coordinates [0-1]
  380. p2.x = (p.x-xmin)/(xmax-xmin);
  381. p2.y = (p.y-ymin)/(ymax-ymin);
  382. // calculate the squared distance
  383. float d = 0.0f;
  384. if (!first)
  385. d = (p2.x-p3.x)*(p2.x-p3.x)+(p2.y-p3.y)*(p2.y-p3.y);
  386. p3.x = p2.x;
  387. p3.y = p2.y;
  388. if (!first)
  389. {
  390. if (d < 1.0f)
  391. point_list.push_back(p2);
  392. else
  393. point_list.pop_back();
  394. }
  395. point_list.push_back(p2);
  396. first = false;
  397. }
  398. }
  399. else
  400. {
  401. for (p.y = ymin+prec; p.y >= ymax-prec; p.y -= prec)
  402. {
  403. get_var_stack()->at(get_var_stack()->size()-1).x = num::float_to_num(p.y);
  404. p.x = num::num_to_float(graph_list[i].graph_node.eval());
  405. // transform to screen coordinates [0-1]
  406. p2.x = (p.x-xmin)/(xmax-xmin);
  407. p2.y = (p.y-ymin)/(ymax-ymin);
  408. // calculate the squared distance
  409. float d = 0.0f;
  410. if (!first)
  411. d = (p2.x-p3.x)*(p2.x-p3.x)+(p2.y-p3.y)*(p2.y-p3.y);
  412. p3.x = p2.x;
  413. p3.y = p2.y;
  414. if (!first)
  415. {
  416. if (d < 1.0f)
  417. point_list.push_back(p2);
  418. else
  419. point_list.pop_back();
  420. }
  421. point_list.push_back(p2);
  422. first = false;
  423. }
  424. }
  425. point_list.pop_back();
  426. }
  427. else
  428. {
  429. point p;
  430. point p2;
  431. point p3; // used for distance checking
  432. bool first = true;
  433. if (xmin < xmax)
  434. {
  435. for (p.x = xmin-prec; p.x <= xmax+prec; p.x += prec)
  436. {
  437. get_var_stack()->at(get_var_stack()->size()-1).x = num::float_to_num(p.x);
  438. p.y = num::num_to_float(graph_list[i].graph_node.eval());
  439. // transform to screen coordinates [0-1]
  440. p2.x = (p.x-xmin)/(xmax-xmin);
  441. p2.y = (p.y-ymin)/(ymax-ymin);
  442. // calculate the squared distance
  443. float d = 0.0f;
  444. if (!first)
  445. d = (p2.x-p3.x)*(p2.x-p3.x)+(p2.y-p3.y)*(p2.y-p3.y);
  446. p3.x = p2.x;
  447. p3.y = p2.y;
  448. if (!first)
  449. {
  450. if (d < 1.0f)
  451. point_list.push_back(p2);
  452. else
  453. point_list.pop_back();
  454. }
  455. point_list.push_back(p2);
  456. first = false;
  457. }
  458. }
  459. else
  460. {
  461. for (p.x = xmin+prec; p.x >= xmax-prec; p.x -= prec)
  462. {
  463. get_var_stack()->at(get_var_stack()->size()-1).x = num::float_to_num(p.x);
  464. p.y = num::num_to_float(graph_list[i].graph_node.eval());
  465. // transform to screen coordinates [0-1]
  466. p2.x = (p.x-xmin)/(xmax-xmin);
  467. p2.y = (p.y-ymin)/(ymax-ymin);
  468. // calculate the squared distance
  469. float d = 0.0f;
  470. if (!first)
  471. d = (p2.x-p3.x)*(p2.x-p3.x)+(p2.y-p3.y)*(p2.y-p3.y);
  472. p3.x = p2.x;
  473. p3.y = p2.y;
  474. if (!first)
  475. {
  476. if (d < 1.0f)
  477. point_list.push_back(p2);
  478. else
  479. point_list.pop_back();
  480. }
  481. point_list.push_back(p2);
  482. first = false;
  483. }
  484. }
  485. point_list.pop_back();
  486. }
  487. // destroy the independent variable
  488. get_var_stack()->pop_back();
  489. }
  490. catch (string e)
  491. {
  492. if (!silent)
  493. log(e);
  494. }
  495. }
  496. // graph the axes
  497. point p1;
  498. point p2;
  499. p1.x = 0.0f;
  500. p1.y = 0.0f;
  501. p2.x = 1.0f;
  502. p2.y = 0.0f;
  503. p1.y = (p1.y-ymin)/(ymax-ymin);
  504. p2.y = (p2.y-ymin)/(ymax-ymin);
  505. point_list.push_back(p1);
  506. point_list.push_back(p2);
  507. p1.x = 0.0f;
  508. p1.y = 0.0f;
  509. p2.x = 0.0f;
  510. p2.y = 1.0f;
  511. p1.x = (p1.x-xmin)/(xmax-xmin);
  512. p2.x = (p2.x-xmin)/(xmax-xmin);
  513. point_list.push_back(p1);
  514. point_list.push_back(p2);
  515. }
  516. catch (string e)
  517. {
  518. if (!silent)
  519. log(e);
  520. }
  521. // redraw the window
  522. wnd->redraw();
  523. // re-enable the nonfatal error system
  524. respond_to_nonfatals(true);
  525. }
  526.  
  527. // the main message handler
  528. void msg_proc(message* msg)
  529. {
  530. if (msg->msg == MSG_CREATE)
  531. {
  532. // activate minimum window size
  533. wnd->set_client_min_size(420, 200);
  534. // set up the menu
  535. wnd->menu_push("File");
  536. menu_file_exit = wnd->menu_item("Exit", true, false);
  537. wnd->menu_pop();
  538. wnd->menu_push("Help");
  539. menu_help_ref = wnd->menu_item("View Reference\tF1", true, false);
  540. wnd->menu_separator();
  541. menu_help_about = wnd->menu_item("About Invariance", true, false);
  542. wnd->menu_pop();
  543. // set up the statusbar
  544. wnd->set_statusbar_enabled(true, "Ready");
  545. // create the "Input" text
  546. wnd->create_ctrl(CTRL_TEXT, "Input:", 8, 4, 200, 20);
  547. // create the "Output" text
  548. wnd->create_ctrl(CTRL_TEXT, "Output:", 8, 52, 200, 20);
  549. // create the "Graph" text
  550. wnd->create_ctrl(CTRL_TEXT, "Graph:", 216, 4, 200, 20);
  551. // create the input box
  552. input = wnd->create_ctrl(CTRL_SINGLE_EDIT, "", 8, 24, 200, 24);
  553. // create the output box
  554. output = wnd->create_ctrl(CTRL_MULTI_EDIT_READONLY, "", 8, 72, 200, 120);
  555. // create the graph box
  556. graph = wnd->create_ctrl(CTRL_OPENGL, "", 216, 24, 200, 168);
  557. // set the font of the input and output boxes
  558. HDC hdc = GetDC(wnd->get_handle());
  559. font = CreateFont(-MulDiv(10, GetDeviceCaps(hdc, LOGPIXELSY), 72), 0, 0, 0, FW_NORMAL, false, false, false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Courier New");
  560. ReleaseDC(wnd->get_handle(), hdc);
  561. SendMessage(wnd->get_ctrl_handle(input), WM_SETFONT, (WPARAM)font, (LPARAM)false);
  562. SendMessage(wnd->get_ctrl_handle(output), WM_SETFONT, (WPARAM)font, (LPARAM)false);
  563. // create the hotkeys
  564. hot_f1 = wnd->create_hotkey(OKC_F1, false, false, false);
  565. // make the window visible
  566. wnd->set_window_visible(true);
  567. // grab the focus of the input box
  568. wnd->grab_ctrl_focus(input);
  569. // initialize the calculating engine
  570. reset();
  571. respond_to_nonfatals(true);
  572. make_graphs(true);
  573. }
  574. if (msg->msg == MSG_HOTKEY)
  575. {
  576. if (msg->ctrl_id == hot_f1)
  577. show_ref();
  578. }
  579. if (msg->msg == MSG_RESIZED)
  580. {
  581. // get the width and height of the client area
  582. int width = wnd->get_client_width();
  583. int height = wnd->get_client_height();
  584. // reposition the controls
  585. wnd->set_ctrl_size(output, 200, height-80);
  586. wnd->set_ctrl_size(graph, width-224, height-32);
  587. // grab the focus of the input box
  588. wnd->grab_ctrl_focus(input);
  589. }
  590. if (msg->msg == MSG_REDRAW)
  591. {
  592. // get the width and height of the client area
  593. int width = wnd->get_client_width();
  594. int height = wnd->get_client_height();
  595. // get the width and height of the control
  596. int graph_width = width-224;
  597. int graph_height = height-32;
  598. // begin rendering on a black graph
  599. wnd->ctrl_begin(graph, 0.0f, 0.0f, 0.0f);
  600. // set the viewport
  601. glViewport(0, 0, graph_width, graph_height);
  602. // set up the projection matrices
  603. glMatrixMode(GL_MODELVIEW);
  604. glLoadIdentity();
  605. glMatrixMode(GL_PROJECTION);
  606. glLoadIdentity();
  607. glOrtho(0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f);
  608. // set the color
  609. glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  610. // render stuff
  611. glBegin(GL_LINES);
  612. for (int i = 0; i < int(point_list.size()); i++)
  613. glVertex2f(point_list[i].x, 1.0f-point_list[i].y);
  614. glEnd();
  615. // finish rendering
  616. wnd->ctrl_end();
  617. }
  618. if (msg->msg == MSG_MENU)
  619. {
  620. // the user wants to quit
  621. if (msg->ctrl_id == menu_file_exit)
  622. wnd_open = false;
  623. // the user wants to learn about the program
  624. if (msg->ctrl_id == menu_help_about)
  625. show_about();
  626. // the user wants to learn about the syntax
  627. if (msg->ctrl_id == menu_help_ref)
  628. show_ref();
  629. }
  630. if (msg->msg == MSG_ACTIVATED)
  631. {
  632. // grab the focus of the input box
  633. wnd->grab_ctrl_focus(input);
  634. }
  635. if (msg->msg == MSG_CLOSE)
  636. wnd_open = false;
  637. if (msg->msg == MSG_DESTROY)
  638. DeleteObject(font);
  639. if (msg->msg == MSG_EDITRETURNED)
  640. {
  641. if (msg->ctrl_id == input)
  642. {
  643. log("");
  644. string str = wnd->get_ctrl_text(input);
  645. try
  646. {
  647. vector <token> token_list = tokenize(str);
  648. bool go_on = true;
  649. if (token_list.size() == 1)
  650. {
  651. if (token_list[0].type == TOK_NAME && token_list[0].text == "rad")
  652. {
  653. go_on = false;
  654. (*get_angle_mode()) = ANGLE_RADIANS;
  655. log("radians mode");
  656. log("> "+str);
  657. make_graphs(true);
  658. }
  659. if (token_list[0].type == TOK_NAME && token_list[0].text == "deg")
  660. {
  661. go_on = false;
  662. (*get_angle_mode()) = ANGLE_DEGREES;
  663. log("degrees mode");
  664. log("> "+str);
  665. make_graphs(true);
  666. }
  667. if (token_list[0].type == TOK_NAME && token_list[0].text == "grad")
  668. {
  669. go_on = false;
  670. (*get_angle_mode()) = ANGLE_GRADS;
  671. log("grads mode");
  672. log("> "+str);
  673. make_graphs(true);
  674. }
  675. if (token_list[0].type == TOK_NAME && token_list[0].text == "zin")
  676. {
  677. go_on = false;
  678. float xmin = num::num_to_float(get_var("xmin"));
  679. float ymin = num::num_to_float(get_var("ymin"));
  680. float xmax = num::num_to_float(get_var("xmax"));
  681. float ymax = num::num_to_float(get_var("ymax"));
  682. float cx = (xmin+xmax)/2.0f;
  683. float cy = (ymin+ymax)/2.0f;
  684. xmin += (cx-xmin)/2.0f;
  685. ymin += (cy-ymin)/2.0f;
  686. xmax += (cx-xmax)/2.0f;
  687. ymax += (cy-ymax)/2.0f;
  688. set_var("xmin", xmin);
  689. set_var("ymin", ymin);
  690. set_var("xmax", xmax);
  691. set_var("ymax", ymax);
  692. log("zoomed in");
  693. log("> "+str);
  694. }
  695. if (token_list[0].type == TOK_NAME && token_list[0].text == "zout")
  696. {
  697. go_on = false;
  698. float xmin = num::num_to_float(get_var("xmin"));
  699. float ymin = num::num_to_float(get_var("ymin"));
  700. float xmax = num::num_to_float(get_var("xmax"));
  701. float ymax = num::num_to_float(get_var("ymax"));
  702. float cx = (xmin+xmax)/2.0f;
  703. float cy = (ymin+ymax)/2.0f;
  704. xmin -= (cx-xmin)/2.0f;
  705. ymin -= (cy-ymin)/2.0f;
  706. xmax -= (cx-xmax)/2.0f;
  707. ymax -= (cy-ymax)/2.0f;
  708. set_var("xmin", xmin);
  709. set_var("ymin", ymin);
  710. set_var("xmax", xmax);
  711. set_var("ymax", ymax);
  712. log("zoomed out");
  713. log("> "+str);
  714. }
  715. if (token_list[0].type == TOK_NAME && token_list[0].text == "reset")
  716. {
  717. go_on = false;
  718. reset();
  719. log("system reset");
  720. log("> "+str);
  721. }
  722. if (token_list[0].type == TOK_NAME && token_list[0].text == "clear")
  723. {
  724. go_on = false;
  725. clear_log();
  726. }
  727. if (token_list[0].type == TOK_NAME && token_list[0].text == "wipe")
  728. {
  729. go_on = false;
  730. graph_list.clear();
  731. point_list.clear();
  732. make_graphs(true);
  733. log("graph wiped");
  734. log("> "+str);
  735. }
  736. if (token_list[0].type == TOK_NAME && token_list[0].text == "exit")
  737. {
  738. go_on = false;
  739. wnd_open = false;
  740. }
  741. }
  742. if (token_list.size() > 1)
  743. {
  744. if (token_list[0].type == TOK_NAME && token_list[1].type == TOK_EQUAL)
  745. {
  746. if (token_list[0].text != "x" && token_list[0].text != "y")
  747. {
  748. go_on = false;
  749. var v;
  750. v.name = token_list[0].text;
  751. vector <token> token_list1;
  752. for (int j = 2; j < int(token_list.size()); j++)
  753. token_list1.push_back(token_list[j]);
  754. node n1(token_list1);
  755. v.x = n1.eval();
  756. get_var_stack()->push_back(v);
  757. log(num::num_to_string(v.x));
  758. log("> "+str);
  759. make_graphs(true);
  760. }
  761. }
  762. if (token_list[0].type == TOK_NAME && token_list[0].text == "der")
  763. {
  764. go_on = false;
  765. vector <token> token_list1;
  766. int scope = 0;
  767. int comma_pos = -1;
  768. for (int j = 1; j < int(token_list.size()); j++)
  769. {
  770. if (token_list[j].type == TOK_BEGINPAREN)
  771. scope--;
  772. if (token_list[j].type == TOK_ENDPAREN)
  773. scope++;
  774. if (scope == 0 && token_list[j].type == TOK_COMMA)
  775. {
  776. comma_pos = j;
  777. break;
  778. }
  779. token_list1.push_back(token_list[j]);
  780. }
  781. if (comma_pos == -1)
  782. throw_error("missing ','", true);
  783. node n1(token_list1);
  784. if (int(token_list.size()) <= comma_pos+1)
  785. throw_error("missing variable name", true);
  786. if (token_list[comma_pos+1].type != TOK_NAME)
  787. throw_error("missing variable name", true);
  788. string varname = token_list[comma_pos+1].text;
  789. if (int(token_list.size()) <= comma_pos+2)
  790. throw_error("missing ','", true);
  791. if (token_list[comma_pos+2].type != TOK_COMMA)
  792. throw_error("missing ','", true);
  793. vector <token> token_list2;
  794. for (int j = comma_pos+3; j < int(token_list.size()); j++)
  795. token_list2.push_back(token_list[j]);
  796. node n2(token_list2);
  797. num inc(get_var("cprec"));
  798. if (num::num_lteq(inc, num::string_to_num("0")))
  799. throw_error("invalid value for cprec", true);
  800. num x1(n2.eval());
  801. num x2(num::num_add(x1, inc));
  802. set_var(varname, x1);
  803. num y1(n1.eval());
  804. get_var_stack()->pop_back();
  805. set_var(varname, x2);
  806. num y2(n1.eval());
  807. get_var_stack()->pop_back();
  808. log(num::num_to_string(num::num_div(num::num_sub(y2, y1), inc)));
  809. log("> "+str);
  810. }
  811. if (token_list[0].type == TOK_NAME && token_list[0].text == "int")
  812. {
  813. go_on = false;
  814. vector <token> token_list1;
  815. int scope = 0;
  816. int comma_pos = -1;
  817. for (int j = 1; j < int(token_list.size()); j++)
  818. {
  819. if (token_list[j].type == TOK_BEGINPAREN)
  820. scope--;
  821. if (token_list[j].type == TOK_ENDPAREN)
  822. scope++;
  823. if (scope == 0 && token_list[j].type == TOK_COMMA)
  824. {
  825. comma_pos = j;
  826. break;
  827. }
  828. token_list1.push_back(token_list[j]);
  829. }
  830. if (comma_pos == -1)
  831. throw_error("missing ','", true);
  832. node n1(token_list1);
  833.  
  834. if (int(token_list.size()) <= comma_pos+1)
  835. throw_error("missing variable name", true);
  836. if (token_list[comma_pos+1].type != TOK_NAME)
  837. throw_error("missing variable name", true);
  838. string varname = token_list[comma_pos+1].text;
  839. if (int(token_list.size()) <= comma_pos+2)
  840. throw_error("missing ','", true);
  841. if (token_list[comma_pos+2].type != TOK_COMMA)
  842. throw_error("missing ','", true);
  843.  
  844. vector <token> token_list2;
  845. scope = 0;
  846. int start_pos = comma_pos+3;
  847. comma_pos = -1;
  848. for (int j = start_pos; j < int(token_list.size()); j++)
  849. {
  850. if (token_list[j].type == TOK_BEGINPAREN)
  851. scope--;
  852. if (token_list[j].type == TOK_ENDPAREN)
  853. scope++;
  854. if (scope == 0 && token_list[j].type == TOK_COMMA)
  855. {
  856. comma_pos = j;
  857. break;
  858. }
  859. token_list2.push_back(token_list[j]);
  860. }
  861. if (comma_pos == -1)
  862. throw_error("missing ','", true);
  863. node n2(token_list2);
  864. vector <token> token_list3;
  865. for (int j = comma_pos+1; j < int(token_list.size()); j++)
  866. token_list3.push_back(token_list[j]);
  867. node n3(token_list3);
  868. num two(num::string_to_num("2"));
  869. num sum(num::string_to_num("0"));
  870. num inc(get_var("cprec"));
  871. if (num::num_lteq(inc, num::string_to_num("0")))
  872. throw_error("invalid value for cprec", true);
  873. num lower(n2.eval());
  874. num upper(n3.eval());
  875. set_var(varname, lower);
  876. bool first = true;
  877. num last_val;
  878. if (num::num_lteq(lower, upper))
  879. {
  880. for (num x(lower); num::num_lteq(x, upper); x = num::num_add(x, inc))
  881. {
  882. get_var_stack()->at(get_var_stack()->size()-1).x = x;
  883. if (first)
  884. sum = num::num_add(sum, n1.eval());
  885. else
  886. {
  887. last_val = n1.eval();
  888. sum = num::num_add(sum, num::num_mul(last_val, two));
  889. }
  890. first = false;
  891. }
  892. get_var_stack()->pop_back();
  893. num interval(num::num_sub(upper, lower));
  894. sum = num::num_sub(sum, last_val);
  895. sum = num::num_div(sum, num::num_mul(two, num::num_div(interval, inc)));
  896. sum = num::num_mul(sum, interval);
  897. }
  898. else
  899. {
  900. for (num x(lower); num::num_gteq(x, upper); x = num::num_sub(x, inc))
  901. {
  902. get_var_stack()->at(get_var_stack()->size()-1).x = x;
  903. if (first)
  904. sum = num::num_add(sum, n1.eval());
  905. else
  906. {
  907. last_val = n1.eval();
  908. sum = num::num_add(sum, num::num_mul(last_val, two));
  909. }
  910. first = false;
  911. }
  912. get_var_stack()->pop_back();
  913. num interval(num::num_sub(upper, lower));
  914. sum = num::num_sub(sum, last_val);
  915. sum = num::num_div(sum, num::num_mul(two, num::num_div(interval, inc)));
  916. sum = num::num_mul(sum, interval);
  917. sum = num::num_neg(sum);
  918. }
  919. log(num::num_to_string(sum));
  920. log("> "+str);
  921. }
  922. if (token_list[0].type == TOK_NAME && token_list[1].type == TOK_BEGINPAREN)
  923. {
  924. bool found = false;
  925. int locus = -1;
  926. for (int j = 2; j < int(token_list.size()); j++)
  927. {
  928. if (token_list[j].type == TOK_EQUAL)
  929. {
  930. found = true;
  931. locus = j;
  932. break;
  933. }
  934. }
  935. if (found)
  936. {
  937. go_on = false;
  938. func f;
  939. f.name = token_list[0].text;
  940. bool expecting_comma = false;
  941. bool success = false;
  942. for (int j = 2; j < int(token_list.size()); j++)
  943. {
  944. if (expecting_comma)
  945. {
  946. if (token_list[j].type == TOK_ENDPAREN)
  947. {
  948. success = true;
  949. break;
  950. }
  951. if (token_list[j].type != TOK_COMMA)
  952. throw_error("missing ','", true);
  953. }
  954. else
  955. {
  956. if (j == 2 && token_list[j].type == TOK_ENDPAREN)
  957. {
  958. success = true;
  959. break;
  960. }
  961. if (token_list[j].type == TOK_NAME)
  962. f.args.push_back(token_list[j].text);
  963. else
  964. throw_error("missing argument name", true);
  965. }
  966. expecting_comma = !expecting_comma;
  967. }
  968. if (!success)
  969. throw_error("missing ')'", true);
  970. vector <token> token_list1;
  971. for (int j = locus+1; j < int(token_list.size()); j++)
  972. token_list1.push_back(token_list[j]);
  973. node n1(token_list1);
  974. f.x = n1;
  975. get_func_stack()->push_back(f);
  976. log("> "+str);
  977. }
  978. }
  979. if (token_list.size() == 2 && token_list[0].type == TOK_NAME && token_list[1].type == TOK_NAME)
  980. {
  981. if (token_list[0].text == "del")
  982. {
  983. go_on = false;
  984. bool found = false;
  985. for (int i = int(get_var_stack()->size())-1; i >= 0; i--)
  986. {
  987. if (get_var_stack()->at(i).name == token_list[1].text)
  988. {
  989. found = true;
  990. get_var_stack()->erase(get_var_stack()->begin()+i);
  991. break;
  992. }
  993. }
  994. if (found)
  995. {
  996. log("variable deleted");
  997. log("> "+str);
  998. }
  999. else
  1000. throw_error("unknown variable: "+token_list[1].text, true);
  1001. }
  1002. }
  1003. if (token_list.size() == 4 && token_list[0].type == TOK_NAME && token_list[1].type == TOK_NAME && token_list[2].type == TOK_BEGINPAREN && token_list[3].type == TOK_ENDPAREN)
  1004. {
  1005. if (token_list[0].text == "del")
  1006. {
  1007. go_on = false;
  1008. bool found = false;
  1009. for (int i = int(get_func_stack()->size())-1; i >= 0; i--)
  1010. {
  1011. if (get_func_stack()->at(i).name == token_list[1].text)
  1012. {
  1013. found = true;
  1014. get_func_stack()->erase(get_func_stack()->begin()+i);
  1015. break;
  1016. }
  1017. }
  1018. if (found)
  1019. {
  1020. log("function deleted");
  1021. log("> "+str);
  1022. }
  1023. else
  1024. throw_error("unknown function: "+token_list[1].text, true);
  1025. }
  1026. }
  1027. if (token_list[0].type == TOK_NAME && token_list[1].type == TOK_EQUAL)
  1028. {
  1029. // ensure that this is an x or y plot
  1030. if (token_list[0].text == "x" || token_list[0].text == "y")
  1031. {
  1032. go_on = false;
  1033. graph_layer g;
  1034. g.graph_var = token_list[0].text;
  1035. // get the expression
  1036. vector <token> token_list1;
  1037. for (int j = 2; j < int(token_list.size()); j++)
  1038. token_list1.push_back(token_list[j]);
  1039. g.graph_node.from_tokens(token_list1);
  1040. // graph
  1041. graph_list.push_back(g);
  1042. make_graphs(false);
  1043. // output the original command
  1044. log("> "+str);
  1045. }
  1046. }
  1047. }
  1048. if (go_on)
  1049. {
  1050. node n(token_list);
  1051. log(num::num_to_string(n.eval()));
  1052. log("> "+str);
  1053. }
  1054. }
  1055. catch (string e)
  1056. {
  1057. log(e);
  1058. log("> "+str);
  1059. respond_to_nonfatals(true);
  1060. }
  1061. wnd->set_ctrl_text(input, "");
  1062. }
  1063. }
  1064. }
  1065.  
  1066. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil)
  1067. {
  1068. // create the window and run the message loop
  1069. wnd_open = true;
  1070. wnd = new window("Invariance", IDI_ICON1, 0, 0, NULL, &msg_proc);
  1071. while (wnd_open) wnd->update();
  1072. delete wnd;
  1073. return 0;
  1074. }
Add Comment
Please, Sign In to add comment