{"id":5448,"date":"2018-04-15T13:00:31","date_gmt":"2018-04-15T13:00:31","guid":{"rendered":"http:\/\/writeasync.net\/?p=5448"},"modified":"2018-04-15T13:38:14","modified_gmt":"2018-04-15T13:38:14","slug":"basic-solutions-expressions","status":"publish","type":"post","link":"http:\/\/writeasync.net\/?p=5448","title":{"rendered":"BASIC solutions: expressions"},"content":{"rendered":"<p><a href=\"http:\/\/writeasync.net\/?p=5444\">Previously<\/a>, I showed the beginnings of a GW-BASIC expression parser. As of now, the parser is essentially feature complete! I fixed the unary minus bug and went on to implement all the remaining features &#8212; mainly relational, logical, and functional operators.<\/p>\n<p>Now having more <a href=\"https:\/\/github.com\/sprache\/Sprache\">Sprache<\/a> experience (and a better understanding of <a href=\"https:\/\/eli.thegreenplace.net\/2012\/08\/02\/parsing-expressions-by-precedence-climbing\/\">precedence climbing<\/a>), most of the work was straightforward. I hit one notable snag along the way when I attempted to support logical AND\/OR for mixed type expressions, e.g. <code>X$=\"str\" AND A=1<\/code>. The grammar I had come up with at that point was too restrictive since it considered string and numeric expressions separately. To get around the parse error, I was forced to <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/b16d60c2fbde78fbf7f2c638143aeb9b70b407b7#diff-c28f4e057de8f074fb00a87ab678c17b\">relax the grammar<\/a>. While there might be a way in Sprache to achieve what I was trying to do, a simple solution escaped me. So technically the expression parser as-is accepts several actually invalid expressions (e.g. <code>\"1\" AND 0<\/code>). In any case, I am not worried much about it as this type of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Semantic_analysis_(compilers)\">semantic analysis<\/a> is typically handled after parsing anyway.<\/p>\n<p>There is still one problem remaining which I have <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/ab1564a53feb58a4a40bad2e9f342bcc696ee02a#diff-c28f4e057de8f074fb00a87ab678c17b\">marked with several skipped tests<\/a>. In an earlier change I <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/e055b227f600d216502be726d7e7cb2fdb4fdf2f#diff-c28f4e057de8f074fb00a87ab678c17b\">disallowed the use of reserved words as identifiers<\/a>; e.g. a variable named <code>LEFT$<\/code> cannot be used since it conflicts with the <a href=\"http:\/\/www.antonis.de\/qbebooks\/gwbasman\/lefts.html\"><code>LEFT$<\/code> function<\/a>. Something about the way this is implemented seems to cause a more restrictive condition where no prefix of a reserved word can be used as an identifier; e.g. the expression <code>LEFT+1<\/code> <em>should be<\/em> allowed since a numeric variable named LEFT is allowed by GW-BASIC. I have chosen to ignore this problem for the time being.<\/p>\n<p>As an added bonus, I decided to implement the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Visitor_pattern\">visitor pattern<\/a> for dealing with the parts of the expression. Traversing a symbolic expression is quite literally a textbook example of the visitor pattern, so it turned out to be a pretty natural fit. It is also a way to allow extensibility of a sort without directly exposing the class hierarchy or the internals of each expression type. The first and only use case right now is a <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/commit\/8ce466c2ff2b14081ec92b6c0ef187e2f177c696#diff-c28f4e057de8f074fb00a87ab678c17b\">visitor for string formatting of the expression<\/a> (which replaced the original <code>ToString()<\/code> overrides). However, I plan to use it later when I get around to implementing the C# code translation part of this project.<\/p>\n<p>For completeness, here is a demonstration of the GW-BASIC equivalent of the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Quadratic_formula\">quadratic formula<\/a>, parsed and written back out as a string, with some spacing to help show the structure:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nstring input = &quot;(-B+SQR(B^2-4*A*C))\/(2*A)&quot;;\r\nstring output = BasicExpression.FromString(input).ToString();\r\nstring expected =\r\n&quot;Div(&quot; +\r\n    &quot;Add(&quot; +\r\n        &quot;Neg(NumV(B)), &quot; +\r\n        &quot;Sqrt(&quot; + \r\n            &quot;Sub(&quot; +\r\n                &quot;Pow(NumV(B), NumL(2)), &quot; +\r\n                &quot;Mult(Mult(NumL(4), NumV(A)), NumV(C))&quot; +\r\n            &quot;)&quot; +\r\n        &quot;)&quot; +\r\n    &quot;), &quot; +\r\n    &quot;Mult(NumL(2), NumV(A))&quot; +\r\n&quot;)&quot;;\r\nbool eq = output == expected; \/\/ true\r\n<\/pre>\n<p>See for yourself by checking out the <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/tree\/master\/projects\/ExpressionSample\">ExpressionSample code on GitHub<\/a>. Come back soon for more GW-BASIC adventures!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Previously, I showed the beginnings of a GW-BASIC expression parser. As of now, the parser is essentially feature complete! I fixed the unary minus bug and went on to implement all the remaining features &#8212; mainly relational, logical, and functional&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[91,41],"tags":[],"class_list":["post-5448","post","type-post","status-publish","format-standard","hentry","category-design","category-tdd"],"_links":{"self":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5448","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5448"}],"version-history":[{"count":4,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5448\/revisions"}],"predecessor-version":[{"id":5452,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5448\/revisions\/5452"}],"wp:attachment":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5448"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5448"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}