{"id":5444,"date":"2018-04-08T13:00:10","date_gmt":"2018-04-08T13:00:10","guid":{"rendered":"http:\/\/writeasync.net\/?p=5444"},"modified":"2018-04-08T01:36:48","modified_gmt":"2018-04-08T01:36:48","slug":"basic-complications-expressions","status":"publish","type":"post","link":"http:\/\/writeasync.net\/?p=5444","title":{"rendered":"BASIC complications: expressions"},"content":{"rendered":"<p>My <a href=\"http:\/\/writeasync.net\/?p=5438\">GW-BASIC saga<\/a> continues. I&#8217;m on the third rewrite now of this &#8220;simple&#8221; translation app. I keep encountering problems that ultimately challenge core design decisions I made early on. Given the time scale and the fact that this is a toy project (and not, say, <a href=\"https:\/\/www.joelonsoftware.com\/2000\/04\/06\/things-you-should-never-do-part-i\/\">the Netscape browser<\/a>), starting over is actually saving me time. On each rewrite, I approach the problem with more clarity than before and, if nothing else, get much more quickly to the point where I throw it all away again. It is a real-ish version of <a href=\"http:\/\/michaelfeathers.typepad.com\/michael_feathers_blog\/2011\/05\/the-carrying-cost-of-code-taking-lean-seriously.html\">Michael Feathers&#8217; &#8220;disappearing code&#8221; experiment<\/a>.<\/p>\n<p>Having seen this problem from a few angles now, I have determined there are at least three &#8220;hard sub-problems&#8221; that must be cracked in order for a reasonable GW-BASIC to C# translator to emerge:<\/p>\n<ol>\n<li>Parsing GW-BASIC statements<\/li>\n<li>Parsing GW-BASIC expressions<\/li>\n<li>Translation to C#<\/li>\n<\/ol>\n<p>It seems obvious in retrospect &#8212; <a href=\"http:\/\/codertom.com\/2014\/12\/exploring-alternatives-to-tautological-tests\/\">tautological<\/a>, almost! &#8212; but there is something to be said for <a href=\"https:\/\/en.wikipedia.org\/wiki\/Experiential_learning\">experiential learning<\/a>. At this point it&#8217;s like I&#8217;m doing a very, very long <a href=\"http:\/\/codekata.com\/\">code kata<\/a>.<\/p>\n<p>Today I want to drill into sub-problem #2 above, GW-BASIC expression parsing. I did not originally distinguish this from plain old GW-BASIC statement parsing, but the most recent rewrite trigger brought it into focus. As a diligent TDD&#8217;er (<a href=\"http:\/\/geepawhill.org\/\">Geepaw Hill<\/a> would be proud!), I had a good set of green tests and was about to implement the next feature &#8212; the &#8216;AND&#8217; <a href=\"http:\/\/www.antonis.de\/qbebooks\/gwbasman\/chapter%206.html\">logical operator<\/a>. Try as I might, I could not get the new failing test to pass without breaking many other tests in wholly unexpected ways. While <a href=\"https:\/\/github.com\/sprache\/Sprache\">Sprache<\/a> had been a big help and massively increased my parsing productivity, the resultant parsers had become hopelessly complicated over time.<\/p>\n<p>Looking back, there was an earlier sign that I was on the wrong path. Almost every new test I was adding ended up in the &#8220;IfThen&#8221; statement parsing fixture. But these were clearly expression parsing tests masquerading as IF\/THEN tests &#8212; if only I had <a href=\"https:\/\/grysz.com\/2015\/11\/05\/listen-to-your-tests-a-real-example\/\">listened to the tests<\/a> sooner.<\/p>\n<p>With the benefit of hindsight, I am going to proceed by building <em>just<\/em> an expression parsing library. Once I can show that parsing expressions works in isolation, I suspect that statement parsing will be much simpler. In essence, I can avert the eventual combinatorial explosion of the earlier tests and cover the two concerns separately (<a href=\"http:\/\/blog.thecodewhisperer.com\/permalink\/surviving-legacy-code-with-golden-master-and-sampling#sampling\">turning products into sums, as @jbrains would say<\/a>).<\/p>\n<p>The <a href=\"https:\/\/github.com\/brian-dot-net\/writeasync\/tree\/master\/projects\/ExpressionSample\">ExpressionSample project on GitHub<\/a> shows the fruits of this labor. It is still a work in progress, but has support for the following:<\/p>\n<ul>\n<li>Numeric and string literals (2, &#8220;xyz&#8221;)<\/li>\n<li>Numeric and string variables (N1, ST$)<\/li>\n<li>Numeric and string arrays with any number of numeric subscripts (AR(2,N))<\/li>\n<li>Additive numeric expressions (2+5-7)<\/li>\n<li>Multiplicative numeric expressions (2*4\/8)<\/li>\n<li>Negation numeric expressions (-X)<\/li>\n<li>Exponential expressions (2^5)<\/li>\n<li>Parenthesized numeric and string expressions ((X+Y)*Z, (&#8220;x&#8221;))<\/li>\n<li>String concatenation (&#8220;x&#8221;+Y$)<\/li>\n<\/ul>\n<p>Annoyingly, it has one bug related to unary minus handling which I have not bothered to address. It will treat the expression &#8220;-1^2&#8221; as &#8220;(-1)^2&#8221; instead of &#8220;-(1^2)&#8221;. Overall it&#8217;s been a mostly fun ~8 hours of work so far.<\/p>\n<p>For completeness, I still need to implement:<\/p>\n<ul>\n<li>Relational operators (=, &lt;, &gt;, etc.)<\/li>\n<li>Logical operators (AND, OR, etc.)<\/li>\n<li>Functional operators (MID$, SQR, etc.)<\/ul>\n<p>All the same, I remain confident that I will be able to continue on this path without another rewrite. We shall see next week!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>My GW-BASIC saga continues. I&#8217;m on the third rewrite now of this &#8220;simple&#8221; translation app. I keep encountering problems that ultimately challenge core design decisions I made early on. Given the time scale and the fact that this is a&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-5444","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\/5444","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=5444"}],"version-history":[{"count":3,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5444\/revisions"}],"predecessor-version":[{"id":5447,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5444\/revisions\/5447"}],"wp:attachment":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5444"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5444"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5444"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}