Testing, coding, in that order.

BASIC complications: expressions

Spread the love

My GW-BASIC saga continues. I’m on the third rewrite now of this “simple” 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, the Netscape browser), 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 Michael Feathers’ “disappearing code” experiment.

Having seen this problem from a few angles now, I have determined there are at least three “hard sub-problems” that must be cracked in order for a reasonable GW-BASIC to C# translator to emerge:

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’er (Geepaw Hill would be proud!), I had a good set of green tests and was about to implement the next feature — the ‘AND’ logical operator. Try as I might, I could not get the new failing test to pass without breaking many other tests in wholly unexpected ways. While Sprache had been a big help and massively increased my parsing productivity, the resultant parsers had become hopelessly complicated over time.

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 “IfThen” statement parsing fixture. But these were clearly expression parsing tests masquerading as IF/THEN tests — if only I had listened to the tests sooner.

With the benefit of hindsight, I am going to proceed by building just 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 (turning products into sums, as @jbrains would say).

Numeric and string arrays with any number of numeric subscripts (AR(2,N))

Additive numeric expressions (2+5-7)

Multiplicative numeric expressions (2*4/8)

Negation numeric expressions (-X)

Exponential expressions (2^5)

Parenthesized numeric and string expressions ((X+Y)*Z, (“x”))

String concatenation (“x”+Y$)

Annoyingly, it has one bug related to unary minus handling which I have not bothered to address. It will treat the expression “-1^2” as “(-1)^2” instead of “-(1^2)”. Overall it’s been a mostly fun ~8 hours of work so far.

For completeness, I still need to implement:

Relational operators (=, <, >, etc.)

Logical operators (AND, OR, etc.)

Functional operators (MID$, SQR, etc.)

All the same, I remain confident that I will be able to continue on this path without another rewrite. We shall see next week!