uCalc API Version: 2.1.3-preview.2 Released: 6/16/2026

Warning

uCalc API Preview Release Notice:The documentation describes the intended behavior of the API. The current preview build contains incomplete features, unoptimized performance, and is subject to breaking changes.

Dynamic Syntax

Product: 

Class: 

Learn how uCalc's grammar can be extended at runtime by defining new operators, keywords, and literal formats.

Remarks

🔧 Dynamic Syntax: Teaching uCalc New Tricks

Most programming languages and parsers have a fixed, unchangeable grammar. The meaning of +, if, or 123 is defined by the language specification and cannot be altered. uCalc is different. Its syntax is dynamic, meaning you can teach the engine new tricks—new operators, new keywords, and even new ways to write numbers—at runtime, without recompiling your application.

This capability transforms uCalc from a simple expression evaluator into a lightweight language workbench, allowing you to create expressive, human-readable Domain-Specific Languages (DSLs) tailored to your specific needs.


1. Creating Custom Operators and Syntax

There are two primary ways to create custom syntax, depending on your needs:

A. Single-Word Operators with DefineOperator

The DefineOperator method is for creating new operators that consist of a single alphanumeric word (like and) or a single symbol (like ##).

For example, let's create a percentof operator:

// Define a 'percentof' operator with the same precedence as multiplication.uc.DefineOperator("{percentage} percentof {total} = (percentage / 100) * total", 60);// The new syntax is immediately available.Console.WriteLine($"15 percentof 200 is {uc.Eval("15 percentof 200")}");

B. Multi-Word Syntax with the Transformer

For more complex, multi-word syntax like 100 USD to EUR, the correct tool is the ExpressionTransformer. It allows you to define flexible, token-aware patterns that are transformed into standard expressions before evaluation.

// Get the transformer that pre-processes expressions.var t = uc.ExpressionTransformer;// Define a rule to handle the multi-word syntax.t.FromTo("{@Number:amount} USD to EUR", "({@Eval: Double(amount) * 0.92})");// The new syntax is now available in any expression.Console.WriteLine($"100 USD is {uc.EvalStr("100 USD to EUR")} EUR");

2. Creating Custom Literals (The Advanced Way)

Extending the syntax to support new literal formats, like C-style hexadecimal numbers (0xFF), is a more advanced process that showcases the power of uCalc's two-stage parsing pipeline. It involves two steps:

  1. Lexical Definition: Teach the tokenizer what the new literal looks like using a regular expression via ExpressionTokens.
  2. Semantic Transformation: Tell the engine what the new literal means by transforming it into a standard expression via the TokenTransformer.

Example: Adding 0x... Hexadecimal Support

// Step 1: Define the lexical rule.// TokenType::TokenTransform tells the parser that this token needs pre-processing.uc.ExpressionTokens.Add("0x[0-9a-fA-F]+", TokenType.TokenTransform);// Step 2: Define the transformation rule.// This captures the hex digits ('val') and replaces the whole token (e.g., "0xFF")// with a standard function call that the engine already understands.uc.TokenTransformer.FromTo("{'0x'}{val:'[0-9a-fA-F]+'}", "BaseConvert('{val}', 16)");// Step 3: Use the new literal format directly in any expression.Console.WriteLine(uc.Eval("0xFF + 1")); // Evaluates 255 + 1

This two-step process allows you to integrate complex, custom syntax seamlessly into the uCalc engine.


💡 Why uCalc? (Comparative Analysis)

  • vs. Parser Generators (ANTLR, Flex/Bison): These are powerful tools, but their grammars are static. To add a new operator or literal, you must modify a grammar file, run a code generator, and recompile your entire application. With uCalc, these changes can be made programmatically at runtime, allowing your application to adapt its own syntax on the fly.

  • vs. Statically-Compiled Languages (C#, C++): In these languages, operator sets and precedence rules are fixed by the language specification. You cannot invent a multi-word USD to EUR syntax. uCalc gives you complete control over the grammar, allowing you to build languages that are far more expressive and domain-specific.

Examples

Creates a domain-specific currency conversion syntax using the ExpressionTransformer, the correct tool for multi-word patterns.
				
					using uCalcSoftware;

var uc = new uCalc();
// Use the ExpressionTransformer for multi-word syntax.
var t = uc.ExpressionTransformer;

// Note: Captured variables are passed to @Eval as text
// Double() converts the text to Double a precision value
uc.Format("Result = Format('{:.2f}', Double(Result))", uc.DataTypeOf("Double"));
t.FromTo("{@Number:amount} USD to EUR", "({@Eval: Double(amount) * 0.92})");
t.FromTo("{@Number:amount} EUR to USD", "({@Eval: Double(amount) / 0.92})");

Console.WriteLine($"100 USD is approx. {uc.EvalStr("100 USD to EUR")} EUR");
Console.WriteLine($"120 EUR is approx. {uc.EvalStr("120 EUR to USD")} USD");
				
			
100 USD is approx. 92.00 EUR
120 EUR is approx. 130.43 USD
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   // Use the ExpressionTransformer for multi-word syntax.
   auto t = uc.ExpressionTransformer();

   // Note: Captured variables are passed to @Eval as text
   // Double() converts the text to Double a precision value
   uc.Format("Result = Format('{:.2f}', Double(Result))", uc.DataTypeOf("Double"));
   t.FromTo("{@Number:amount} USD to EUR", "({@Eval: Double(amount) * 0.92})");
   t.FromTo("{@Number:amount} EUR to USD", "({@Eval: Double(amount) / 0.92})");

   cout << "100 USD is approx. " << uc.EvalStr("100 USD to EUR") << " EUR" << endl;
   cout << "120 EUR is approx. " << uc.EvalStr("120 EUR to USD") << " USD" << endl;
}
				
			
100 USD is approx. 92.00 EUR
120 EUR is approx. 130.43 USD
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      '// Use the ExpressionTransformer for multi-word syntax.
      Dim t = uc.ExpressionTransformer
      
      '// Note: Captured variables are passed to @Eval as text
      '// Double() converts the text to Double a precision value
      uc.Format("Result = Format('{:.2f}', Double(Result))", uc.DataTypeOf("Double"))
      t.FromTo("{@Number:amount} USD to EUR", "({@Eval: Double(amount) * 0.92})")
      t.FromTo("{@Number:amount} EUR to USD", "({@Eval: Double(amount) / 0.92})")
      
      Console.WriteLine($"100 USD is approx. {uc.EvalStr("100 USD to EUR")} EUR")
      Console.WriteLine($"120 EUR is approx. {uc.EvalStr("120 EUR to USD")} USD")
   End Sub
End Module
				
			
100 USD is approx. 92.00 EUR
120 EUR is approx. 130.43 USD
Defines a custom `sum_to` operator to calculate the sum of a numeric range, demonstrating a single-word operator.
				
					using uCalcSoftware;

var uc = new uCalc();
// Define the variables that the operator's expression will use.
uc.DefineVariable("i");
uc.DefineVariable("total");

// Define a new 'sum_to' operator at runtime.
// It uses the built-in ForLoop function to sum numbers into the 'total' variable.
uc.DefineOperator("{start} sum_to {end} = total = 0; ForLoop(i, start, end, 1, total = total + i)", 50);

// Use the new operator. The result is stored in the 'total' variable.
uc.Eval("1 sum_to 5");

Console.WriteLine($"The sum from 1 to 5 is: {uc.Eval("total")}");
				
			
The sum from 1 to 5 is: 15
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   // Define the variables that the operator's expression will use.
   uc.DefineVariable("i");
   uc.DefineVariable("total");

   // Define a new 'sum_to' operator at runtime.
   // It uses the built-in ForLoop function to sum numbers into the 'total' variable.
   uc.DefineOperator("{start} sum_to {end} = total = 0; ForLoop(i, start, end, 1, total = total + i)", 50);

   // Use the new operator. The result is stored in the 'total' variable.
   uc.Eval("1 sum_to 5");

   cout << "The sum from 1 to 5 is: " << uc.Eval("total") << endl;
}
				
			
The sum from 1 to 5 is: 15
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      '// Define the variables that the operator's expression will use.
      uc.DefineVariable("i")
      uc.DefineVariable("total")
      
      '// Define a new 'sum_to' operator at runtime.
      '// It uses the built-in ForLoop function to sum numbers into the 'total' variable.
      uc.DefineOperator("{start} sum_to {end} = total = 0; ForLoop(i, start, end, 1, total = total + i)", 50)
      
      '// Use the new operator. The result is stored in the 'total' variable.
      uc.Eval("1 sum_to 5")
      
      Console.WriteLine($"The sum from 1 to 5 is: {uc.Eval("total")}")
   End Sub
End Module
				
			
The sum from 1 to 5 is: 15
Internal Test: Implements C-style hexadecimal literals (e.g., 0xFF) by adding a new token rule and a token transformation.
				
					using uCalcSoftware;

var uc = new uCalc();
// 1. Define the lexical rule.
// The regex matches '0x' followed by hex digits.
// The TokenType::TokenTransform tells the parser to pre-process this token.
uc.ExpressionTokens.Add("0x[0-9a-fA-F]+", TokenType.TokenTransform);

// 2. Define the transformation rule.
// This captures the hex digits and replaces the whole token with a call to BaseConvert.
uc.TokenTransformer.FromTo("{'0x'}{val:'[0-9a-fA-F]+'}", "BaseConvert('{val}', 16)");

// 3. Now, the new literal format can be used in expressions.
Console.WriteLine(uc.Eval("0xFF + 0xA")); // 255 + 10
Console.WriteLine(uc.EvalStr("Hex(0x100)")); // Hex(256)
				
			
265
100
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   // 1. Define the lexical rule.
   // The regex matches '0x' followed by hex digits.
   // The TokenType::TokenTransform tells the parser to pre-process this token.
   uc.ExpressionTokens().Add("0x[0-9a-fA-F]+", TokenType::TokenTransform);

   // 2. Define the transformation rule.
   // This captures the hex digits and replaces the whole token with a call to BaseConvert.
   uc.TokenTransformer().FromTo("{'0x'}{val:'[0-9a-fA-F]+'}", "BaseConvert('{val}', 16)");

   // 3. Now, the new literal format can be used in expressions.
   cout << uc.Eval("0xFF + 0xA") << endl; // 255 + 10
   cout << uc.EvalStr("Hex(0x100)") << endl; // Hex(256)
}
				
			
265
100
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      '// 1. Define the lexical rule.
      '// The regex matches '0x' followed by hex digits.
      '// The TokenType::TokenTransform tells the parser to pre-process this token.
      uc.ExpressionTokens.Add("0x[0-9a-fA-F]+", TokenType.TokenTransform)
      
      '// 2. Define the transformation rule.
      '// This captures the hex digits and replaces the whole token with a call to BaseConvert.
      uc.TokenTransformer.FromTo("{'0x'}{val:'[0-9a-fA-F]+'}", "BaseConvert('{val}', 16)")
      
      '// 3. Now, the new literal format can be used in expressions.
      Console.WriteLine(uc.Eval("0xFF + 0xA")) '// 255 + 10
      Console.WriteLine(uc.EvalStr("Hex(0x100)")) '// Hex(256)
   End Sub
End Module
				
			
265
100