-
Notifications
You must be signed in to change notification settings - Fork 0
FAQ
CDTk (Compiler Description Toolkit) is a modern, strongly-typed .NET library for building compilers, transpilers, and code generators. It provides a unified, declarative pipeline with a focus on safety, performance, and extensibility. Core components include:
- TokenSet: Defines lexical patterns (tokens).
- RuleSet: Structures grammar rules and creates ASTs.
- MapSet: Generates target output or code from ASTs.
- Model System: Adds semantic processing and intermediate transformations.
Starting with Version 8, CDTk introduces:
- Field-Based Identity: Use variable-bound references for tokens, rules, and mappings.
- Model System: Enable advanced semantic transformations across the pipeline.
- Validation System: Validate grammars and mappings before runtime.
CDTk is ideal for:
- Domain-Specific Languages (DSLs): Simplify language creation for niche tasks.
- Code Generators and Transpilers: Convert code between formats (e.g., SQL to JSON).
- General Compiler Development: Create robust and scalable compilers with minimal boilerplate.
- Teaching Compiler Construction: Perfect for academics and tutorials due to clarity and strong typing.
- Data Transformers: Convert structured data (e.g., CSV to JSON) with parsing pipelines.
CDTk targets .NET 7 and above. Using upgraded C# features, the library ensures strong support for modern APIs, generics, and memory-safe code standards.
Key improvements in v8 include:
- Field-Based Grammar: Rules and tokens are defined as fields in inheritable classes, simplifying rule identity and eliminating generics.
- Reference Identity: All elements are resolved via object references, not string-based lookups.
- Model System: Introduce intermediate transformation layers between ASTs and mappings.
-
Validation: Add declarative
.Validate()calls to ensure grammar correctness during pre-compilation. - Multi-Target Compilation: Compile once and generate outputs across multiple formats (e.g., Python, C, JavaScript).
Here’s a minimal example using CDTk v8:
// Define TokenSet
class Tokens : TokenSet
{
public Token Number = @"\d+";
public Token Identifier = @"[A-Za-z_][A-Za-z0-9_]*";
public Token Equals = @"=";
}
// Define RuleSet
class Rules : RuleSet
{
public Rule AssignmentNode = new Rule("variable:@Identifier '=' value:@Number")
.Returns("variable", "value");
}
// Define MapSet
class Mappings : MapSet
{
public Map AssignmentNode = "let {variable} = {value};";
}
// Build and compile
var compiler = new Compiler()
.WithTokens(new Tokens())
.WithRules(new Rules())
.WithTarget(new Mappings())
.Build();
var result = compiler.Compile("x = 42;");
Console.WriteLine(result.Output); // Outputs: let x = 42;Visit Examples.md to explore:
- Calculator compilers
- Multi-language transpilers
- Simple JSON parsers
- Expression evaluators
- Mini-programming languages
- Check token order: CDTk processes tokens sequentially. Place more specific patterns before generic ones.
// Incorrect
public Token Identifier = @"[A-Za-z_][A-Za-z0-9_]*"; // Too generic
public Token Keyword = @"if|else|while"; // Won't match
// Correct
public Token Keyword = @"if|else|while"; // Keywords first
public Token Identifier = @"[A-Za-z_][A-Za-z0-9_]*"; // Identifier later- Use tools like Regex101 to validate patterns.
Add .Ignore() to tokens:
public Token Whitespace = new Token(@"\s+").Ignore();Ignored tokens are matched but excluded from downstream processing.
Use RegexOptions.Singleline:
public Token BlockComment = new Token(@"/\*.*?\*/", RegexOptions.Singleline).Ignore();Define a regex for escape sequences:
public Token StringLiteral = @"""([^""\\]|\\.)*""";This matches strings with escaped characters like \" and \n.
-
Confirm that tokens use
@in rule definitions:// Incorrect (missing `@`) new Rule("Identifier '=' Number"); // Correct (reference tokens with `@`) new Rule("variable:@Identifier '=' value:@Number");
-
Check the precedence of alternations and ensure proper grouping with parentheses:
new Rule("Factor", "@Number | '(' Expression ')'");
Use ? for optional components:
public Rule VariableDecl = new Rule("@Type @Identifier ('=' Expression)?")
.Returns("type", "name", "init");Use * (zero or more) or + (one or more repetitions):
public Rule ArgList = new Rule("Expression (',' Expression)*").Returns("args");
public Rule StatementBlock = new Rule("'{' Statement* '}'").Returns("statements");Models are lazy semantic processors that work between AST generation and mappings. They enable custom, intermediate processing for validations, transformations, and enhanced mappings.
Define a class extending Model:
class MyModel : Model
{
private readonly __Ast _ast;
public MyModel(__Ast ast)
{
_ast = ast;
}
public override object Build(object input)
{
if (input is AstNode node)
{
return new { TransformedNode = node.GetString("variable").ToUpper() };
}
return input;
}
}
// Adding to MapSet
class Mappings : MapSet
{
public MyModel Model => new MyModel(__Ast!);
}- Sanitizing AST nodes: Clean variable declarations or correct invalid identifiers.
- Adding metadata: Insert semantic data for specialized mappings.
-
Ensure node types match between
.Returns()and mapping templates:public Map AssignmentNode = "let {variable} = {value};";
-
Validate placeholders: Ensure
{fieldName}matches the field declarations in.Returns().
Yes, incorporate custom models or rules:
class DynamicMappings : MapSet
{
public Map ValidatedOutput = "let {variable}[opt |= {sanitizedValue}];";
}