Everytime I look, I find another stinky wart in my code, lol.
Instead of adding any type of factory or if/else/switch facility to allow me to create specific pcode instances, I made the operator precedence table very very explicit. So when I reduce a '*' I know to generate a MultiplyPcode instance. Previously I generated a generic "binary" pcode with "*" as an attribute. But then getting from "*" a representative class required a Factory or switch().
Now, the explicit parser table works great though adding new Redux/Pcode/Executable classes is tedious. But there's nothing to break in the approach so once it works, it will work forever. But is it too explicit? Individual rows for every possible operator and ID type is great, totally accurate, and easy to use. But the table is getting unweildy. The very incomplete table is already 15x15 or so. I can see it floating up to 21x21.
Currently, the table uses the stack's topmost operator on one axis and the input operator on the other. The intersection identifies the action to perform.
This works great until you get 6 operators with the same precedence. Like >, >=, ==, !=, <=, <. Now I'm adding a huge number of virtually identical cells to the table. Perhaps associating the operators with a numeric precedence would have allowed the table to be structured differently and a lot smaller. Instead of:
action = crossIndex(stackOp, inputOp)
where action is shift() or MultiplyReduce(), I could have done:
diffTypeOfAction = crossIndex(stackOp.precedence, inputOp.precedence)
And now if diffTypeOfAction is reduce(), you execute stackOp.reduce(). That extra step seems to allow the table to be about 1/4 the current size without any loss of functionality. Since my operators are all left-associative and of consistent precedence (there is no a>b>c>a type of precedence chain) I think I can create a reasonable set of abstract precedences.
Making the table too explicit caused me to make another poor decision. I fudged ID-type tokens. Because I was tired of adding rows and columns to the precedence table one night, I slammed the Token's class to VARIABLE so I didn't have to mess with numeric or string constants. I knew I'd be revisiting it. But like 3 of the 4 Ghostbusters, I didn't know the form of The Destroyer. In my case, it's a bunch of Executables that don't know the type of their operands! D'oh!
Perhaps the Stay Puft marshmallow man would have been better.