As great as Mathieu Jacques’s MTParser is, it only supports double-precision floating point numbers and it only works with .NET through a COM interface, which means I have less control over the parser and I have to register the dll. Therefore, GlassCalc 2 will feature a new parser which I am writing from the ground up. I call this new parser GCParser. I am awesome at naming things.
Here is a fairly technical description of how GCParser will work:
Design Goals of GCParser
- The parser will operate on objects deriving from GCObject. This is a completely generic class, and in fact, the only function a GCObject must have converts the object to a string so it can be displayed.
- GCParser will have two types of GCObject out-of-the-metaphorical-box: numbers and arrays. Arrays are lists of GCObjects. This means GCParser will support vector operations, and since you can make arrays of arrays, probably matrix operations too.
a = [1, 2, 3]is a 3-element array.
aretrieves the first element of the array.
- GCObjects can have properties and functions. For instance, arrays will have x, y, and z properties to make 3d vector operations easy.
[1, 2, 3].xwill return
[2, 3, 1].sort()would return
[1, 2, 3].
- GCParser will be able to operate on multiple types at once. For instance, when executing
2 * [3, 4]the parser would search for a Multiply function taking two arguments of types GCNumber and GCArray. This expression would evaluate to
[6, 8]. If no function was found, the parser would throw a type error.
- GCParser will be extensible. Extensions will be able to define not only constants and functions, but new GCObject types as well. For instance, a complex numbers extension could define a GCComplexNumber class, functions for operating on complex numbers, and a constant i. Since the parser will only create numbers and arrays normally, the extension would also need to define a constructor function,
Complex(real, imag), to make complex numbers. If the extension defined functions for adding/multiplying numbers and complex numbers together, the expression
1 + 2iwould also work. The parser would interpret this as
(number: 1) + ((number: 2) * (complex: 0 + i)).
- I haven’t figured out how this would work yet, but I want GCParser to support expressions like
[1, 2, 3].sort((a,b) => b<a). This would send a predicate function to the sort function telling it how to sort—in this case, sort descending. Likewise,
Sum(n => 0.5^n, 1, 50)would sum 0.5n from n = 1 to 50.
- Parsing occurs in three stages: tokenization, parsing and evaluation. Tokenization takes the expression and figures out what all the individual parts mean. It also generates a structure which the syntax highlighter can use instead of the convoluted regular expression system GlassCalc currently uses. Parsing takes the tokenized expression and converts it into a binary tree of operations. Evaluation traverses the tree, running each operation until it gets a final result. Parsing and evaluation will not run on the UI thread, so the program won’t freeze up if you run a long calculation.
Things That Are Not Design Goals of GCParser
- Be really fast.
- GlassCalc 2 will have a new parser. It will be magic, rainbows and unicorns. It will calculate just about anything.
- If it can’t calculate something, you can probably write an extension so it can.
So, when will it be done? Eventually. I have the tokenizer mostly complete. I am waiting for .NET 4.5 to be released before I start work on the UI, as I will make use of its new asynchronous stuff.