Pure ISO Scryer Prolog regular expression engine supporting DCG non-terminals, direct character lists, DFA, and cyclic tree automata
6
stars
0
commits
Prolog
primary language
Sep 3, 2026
updated
regexp)A pure, ISO-compliant regular expression engine providing both Definite Clause Grammar (DCG) non-terminal and direct character list (chars) matching interfaces for Scryer Prolog and other ISO-compliant Prolog implementations.
Software Development :: Libraries :: Prolog Modules, Text Processing :: Pattern Matching :: Regular Expressions, Compilers/Interpreters :: Definite Clause Grammars (DCG)Prolog :: ISO-CompliantScryer Prolog, Trealla Prolog, Tau Prolog, GNU PrologUnlicense (Public Domain)The primary goals of this project are:
REGEXP) matching library for Scryer Prolog and other ISO Prolog systems (such as Trealla Prolog, Tau Prolog, GNU Prolog, Ciao, etc.) without relying on system-dependent C primitives or foreign function interfaces.phrase(re_match(Pattern, Match), Input)) for seamlessly embedding regular expression rules inside Prolog DCG parsing logic.re_match(Pattern, Input), re_match(Pattern, Input, Rest), re_match_groups/4-5, re_match_named/4-5) for direct string matching without needing phrase/2-3 wrappers.src/core/regexp_tree.pl): Re-exported by default via src/regexp.pl; fast, pure if_/3-driven cyclic term finite state automaton matching.src/core/regexp_compile_dcg.pl): Direct substitute; full-featured regex parser with group extractions, lookaheads, and inline flags.src/core/regexp_compile_dfa.pl): Direct substitute; deterministic finite automaton execution.Bakage is optional. Because regexp is written in pure ISO Prolog, you can use it either with Bakage or by directly importing the files into any Prolog project.
bakage)Add to scryer-manifest.pl:
dependencies([
dependency("regexp", git("https://github.com/dougransom/regexp_dcg.git"))
]).
Install Dependencies:
scryer-prolog bakage.pl -- install
Import in Prolog Code:
:- use_module(bakage).
:- use_module(pkg(regexp)).
% DCG Interface
?- phrase(re_match("[a-z]+", Match), "hello").
% Direct Characters Interface
?- re_match("[a-z]+", "hello").
Clone or Download the Repository:
git clone https://github.com/dougransom/regexp_dcg.git
Direct Import via use_module/1:
Import regexp.pl using its relative path:
:- use_module('path/to/regexp_dcg/src/regexp').
% Direct Character Matching (Rational Tree Engine by default)
?- re_match("[a-z]+", "hello").
% DCG Non-Terminal Matching
?- phrase(re_match("[a-z]+", Match), "hello").
% Or import DCG engine directly as a substitute:
:- use_module('path/to/regexp_dcg/src/core/regexp_compile_dcg').
regexp)The main entry point for matching patterns is the regexp module. By default, it uses the Rational Tree Automaton implementation (regexp_tree). You can switch the active engine globally by asserting user:regexp_mode(dcg) or user:regexp_mode(dfa) prior to or after importing, or per-call via mode options ([mode(dcg)], [mode(dfa)]).
% Global mode selection before or after importing regexp:
?- assertz(user:regexp_mode(dcg)).
true.
?- use_module('src/regexp').
true.
re_match/2-3)Match character lists directly without needing DCG phrase/2-3 wrappers:
?- use_module('src/regexp').
true.
% Direct full match (anchored, Rational Tree engine default)
?- re_match("a*b", "aaab").
true.
% Direct match returning unparsed remainder
?- re_match("a*b", "aaabc", Rest).
Rest = "c"
; false.
re_match//1-2)Use re_match non-terminals directly inside phrase/2, phrase/3, or embedded within custom DCG rules:
% Match prefix and capture substring inside DCG
?- phrase(re_match("a*b", Match), "aaabc", Rest).
Match = "aaab", Rest = "c"
; false.
% Simple prefix matching (boolean / non-capturing)
?- phrase(re_match("[a-z]+"), "hello world", Rest).
Rest = " world"
; false.
re_match_groups & re_match_named)Extract numbered or named capturing groups via direct predicates or DCG non-terminals:
% Direct group extraction
?- re_match_groups("(\\d+)-(\\w+)", "123-abc", Match, Groups).
Match = "123-abc", Groups = ["123", "abc"]
; false.
% Named capturing groups inside DCG
?- phrase(re_match_named("(?P<year>\\d{4})-(?P<month>\\d{2})", Match, Named), "2026-08").
Match = "2026-08", Named = [year-"2026", month-"08"]
; false.
re_compile/2)For maximum efficiency when evaluating the same pattern against many inputs, pre-compile the pattern into a reusable structure:
?- re_compile("[0-9]+", Compiled),
re_match(Compiled, "12345extra", Rest).
Compiled = compiled(call(regexp_dcg:dcg_concat([call(regexp_dcg:dcg_plus(call(regexp_dcg:dcg_class([range(48,57)]))))])), 0),
Rest = "extra"
; false.
The library is structured into modular layers:
regexp_dcg.pl (DCG Backtracking Engine):
Full-featured DCG backtracking regular expression engine with capturing groups, lookaheads, and inline flags.
regexp_tree.pl (Rational Tree Automaton Engine):
Fast, pure if_/3-driven cyclic term finite state automaton matching.
src/regexp_ast.pl (Parser & Tokenizer):
Parses raw regular expression character lists into an Abstract Syntax Tree (AST) representation (lit/1, class/1, group/1, star/1, etc.). Implements tokenizers (re_token//1) and POSIX class parsing.
src/regexp_compile_dfa.pl (Experimental DFA Engine):
An experimental NFA/DFA engine for benchmarking and comparing performance against the primary DCG and Tree engines.
In ISO Prolog systems treating double_quotes as character lists (chars), strings represent sequences of native character code points. This library supports international character matching out of the box:
"café"), Greek ("αβγ"), Chinese Hanzi ("你好"), Emojis ("🚀😀"), and Klingon script ("Qapla'" / PUA code points "\uF8D5\uF8D4\uF8E1\uF8D5\uF8DF")..: Correctly matches 1 Unicode character (code point).[caféñ] or [α-ω] match by Unicode code points.[!NOTE] Case-Insensitivity Limitation (
(?i)): Inline flag(?i)case folding is currently scoped to ASCII characters ('A'-'Z'$\leftrightarrow$'a'-'z'). Non-ASCII international uppercase/lowercase foldings (e.g.'É'$\leftrightarrow$'é') are not automatically folded by(?i).
examples/international/multilingual_matching.pl.examples/toml/)The repository includes a complete TOML Light Parser Example under examples/toml/, demonstrating how regexp_dcg functions as a clean tokenizer combined with Prolog DCG grammars to parse configuration files into structured AST terms.
title = "My App", count = 42, debug = trueports = [8000, 8001, 8002], names = ["a", "b", "c"][server] (headers and scope management)database.host = "db.local", database.port = 5432owner = { name = "Doug", email = "doug@example.com" }# This is a commentexamples/toml/toml_tokenizer.pl):
Demonstrates regexp_dcg features:
[A-Za-z0-9_-]+"([^"\\]|\\.)*"-?[0-9]+(\.[0-9]+)?)true|false#.*$examples/toml/toml_parser.pl):
Recursive DCG rules building AST terms (toml([kv(...), table(...), comment(...)])) handling multi-line files and nested table scopes.examples/toml/sample.toml & examples/toml/parse_sample.pl):
Execute the TOML parser pipeline inside the examples/toml directory:
cd examples/toml
scryer-prolog parse_sample.pl -g main
(or: nice scryer-safe parse_sample.pl -g main)Detailed Documentation: See docs/usage.md for full feature documentation and expected Scryer Prolog REPL outputs for all supported regular expression constructs.
Unit Tests:
tests/test_regexp_dcg.pl — Core DCG engine matching tests.tests/test_regexp_tree.pl — Rational Tree Automaton engine tests.tests/test_international.pl — Multilingual character tests (French, Greek, Chinese, Emoji, Klingon).tests/test_regexp_ast.pl — Regex parser and AST construction tests.tests/test_re_token.pl — Regex tokenization (re_token//1), metacharacter, and character class tests.tests/test_exports_match.pl — Module export interface consistency tests across all engine implementations.Testing Requirements:
Run the test suite with:
make test
Drawing inspiration from finite state machine compilers like Ragel and Kleene algebra theory, Prolog is uniquely suited to evolve this regular expression engine beyond string matching into an algebraic reasoning and state machine synthesis tool:
Algebraic Reasoning & Set Operations:
Induction & Shortest Regular Expression Synthesis:
Brzozowski & Antimirov Derivatives:
The Ragel Connection (State Machine Compilation & Embedded Actions):
The regular expression syntax and semantics supported by this library are inspired by Python 3.14 regular expressions (re):
Prolog
96.9%
Makefile
3.1%
Pure ISO Scryer Prolog regular expression engine supporting DCG non-terminals, direct character lists, DFA, and cyclic tree automata
6
stars
0
commits
Prolog
primary language
Sep 3, 2026
updated
regexp)A pure, ISO-compliant regular expression engine providing both Definite Clause Grammar (DCG) non-terminal and direct character list (chars) matching interfaces for Scryer Prolog and other ISO-compliant Prolog implementations.
Software Development :: Libraries :: Prolog Modules, Text Processing :: Pattern Matching :: Regular Expressions, Compilers/Interpreters :: Definite Clause Grammars (DCG)Prolog :: ISO-CompliantScryer Prolog, Trealla Prolog, Tau Prolog, GNU PrologUnlicense (Public Domain)The primary goals of this project are:
REGEXP) matching library for Scryer Prolog and other ISO Prolog systems (such as Trealla Prolog, Tau Prolog, GNU Prolog, Ciao, etc.) without relying on system-dependent C primitives or foreign function interfaces.phrase(re_match(Pattern, Match), Input)) for seamlessly embedding regular expression rules inside Prolog DCG parsing logic.re_match(Pattern, Input), re_match(Pattern, Input, Rest), re_match_groups/4-5, re_match_named/4-5) for direct string matching without needing phrase/2-3 wrappers.src/core/regexp_tree.pl): Re-exported by default via src/regexp.pl; fast, pure if_/3-driven cyclic term finite state automaton matching.src/core/regexp_compile_dcg.pl): Direct substitute; full-featured regex parser with group extractions, lookaheads, and inline flags.src/core/regexp_compile_dfa.pl): Direct substitute; deterministic finite automaton execution.Bakage is optional. Because regexp is written in pure ISO Prolog, you can use it either with Bakage or by directly importing the files into any Prolog project.
bakage)Add to scryer-manifest.pl:
dependencies([
dependency("regexp", git("https://github.com/dougransom/regexp_dcg.git"))
]).
Install Dependencies:
scryer-prolog bakage.pl -- install
Import in Prolog Code:
:- use_module(bakage).
:- use_module(pkg(regexp)).
% DCG Interface
?- phrase(re_match("[a-z]+", Match), "hello").
% Direct Characters Interface
?- re_match("[a-z]+", "hello").
Clone or Download the Repository:
git clone https://github.com/dougransom/regexp_dcg.git
Direct Import via use_module/1:
Import regexp.pl using its relative path:
:- use_module('path/to/regexp_dcg/src/regexp').
% Direct Character Matching (Rational Tree Engine by default)
?- re_match("[a-z]+", "hello").
% DCG Non-Terminal Matching
?- phrase(re_match("[a-z]+", Match), "hello").
% Or import DCG engine directly as a substitute:
:- use_module('path/to/regexp_dcg/src/core/regexp_compile_dcg').
regexp)The main entry point for matching patterns is the regexp module. By default, it uses the Rational Tree Automaton implementation (regexp_tree). You can switch the active engine globally by asserting user:regexp_mode(dcg) or user:regexp_mode(dfa) prior to or after importing, or per-call via mode options ([mode(dcg)], [mode(dfa)]).
% Global mode selection before or after importing regexp:
?- assertz(user:regexp_mode(dcg)).
true.
?- use_module('src/regexp').
true.
re_match/2-3)Match character lists directly without needing DCG phrase/2-3 wrappers:
?- use_module('src/regexp').
true.
% Direct full match (anchored, Rational Tree engine default)
?- re_match("a*b", "aaab").
true.
% Direct match returning unparsed remainder
?- re_match("a*b", "aaabc", Rest).
Rest = "c"
; false.
re_match//1-2)Use re_match non-terminals directly inside phrase/2, phrase/3, or embedded within custom DCG rules:
% Match prefix and capture substring inside DCG
?- phrase(re_match("a*b", Match), "aaabc", Rest).
Match = "aaab", Rest = "c"
; false.
% Simple prefix matching (boolean / non-capturing)
?- phrase(re_match("[a-z]+"), "hello world", Rest).
Rest = " world"
; false.
re_match_groups & re_match_named)Extract numbered or named capturing groups via direct predicates or DCG non-terminals:
% Direct group extraction
?- re_match_groups("(\\d+)-(\\w+)", "123-abc", Match, Groups).
Match = "123-abc", Groups = ["123", "abc"]
; false.
% Named capturing groups inside DCG
?- phrase(re_match_named("(?P<year>\\d{4})-(?P<month>\\d{2})", Match, Named), "2026-08").
Match = "2026-08", Named = [year-"2026", month-"08"]
; false.
re_compile/2)For maximum efficiency when evaluating the same pattern against many inputs, pre-compile the pattern into a reusable structure:
?- re_compile("[0-9]+", Compiled),
re_match(Compiled, "12345extra", Rest).
Compiled = compiled(call(regexp_dcg:dcg_concat([call(regexp_dcg:dcg_plus(call(regexp_dcg:dcg_class([range(48,57)]))))])), 0),
Rest = "extra"
; false.
The library is structured into modular layers:
regexp_dcg.pl (DCG Backtracking Engine):
Full-featured DCG backtracking regular expression engine with capturing groups, lookaheads, and inline flags.
regexp_tree.pl (Rational Tree Automaton Engine):
Fast, pure if_/3-driven cyclic term finite state automaton matching.
src/regexp_ast.pl (Parser & Tokenizer):
Parses raw regular expression character lists into an Abstract Syntax Tree (AST) representation (lit/1, class/1, group/1, star/1, etc.). Implements tokenizers (re_token//1) and POSIX class parsing.
src/regexp_compile_dfa.pl (Experimental DFA Engine):
An experimental NFA/DFA engine for benchmarking and comparing performance against the primary DCG and Tree engines.
In ISO Prolog systems treating double_quotes as character lists (chars), strings represent sequences of native character code points. This library supports international character matching out of the box:
"café"), Greek ("αβγ"), Chinese Hanzi ("你好"), Emojis ("🚀😀"), and Klingon script ("Qapla'" / PUA code points "\uF8D5\uF8D4\uF8E1\uF8D5\uF8DF")..: Correctly matches 1 Unicode character (code point).[caféñ] or [α-ω] match by Unicode code points.[!NOTE] Case-Insensitivity Limitation (
(?i)): Inline flag(?i)case folding is currently scoped to ASCII characters ('A'-'Z'$\leftrightarrow$'a'-'z'). Non-ASCII international uppercase/lowercase foldings (e.g.'É'$\leftrightarrow$'é') are not automatically folded by(?i).
examples/international/multilingual_matching.pl.examples/toml/)The repository includes a complete TOML Light Parser Example under examples/toml/, demonstrating how regexp_dcg functions as a clean tokenizer combined with Prolog DCG grammars to parse configuration files into structured AST terms.
title = "My App", count = 42, debug = trueports = [8000, 8001, 8002], names = ["a", "b", "c"][server] (headers and scope management)database.host = "db.local", database.port = 5432owner = { name = "Doug", email = "doug@example.com" }# This is a commentexamples/toml/toml_tokenizer.pl):
Demonstrates regexp_dcg features:
[A-Za-z0-9_-]+"([^"\\]|\\.)*"-?[0-9]+(\.[0-9]+)?)true|false#.*$examples/toml/toml_parser.pl):
Recursive DCG rules building AST terms (toml([kv(...), table(...), comment(...)])) handling multi-line files and nested table scopes.examples/toml/sample.toml & examples/toml/parse_sample.pl):
Execute the TOML parser pipeline inside the examples/toml directory:
cd examples/toml
scryer-prolog parse_sample.pl -g main
(or: nice scryer-safe parse_sample.pl -g main)Detailed Documentation: See docs/usage.md for full feature documentation and expected Scryer Prolog REPL outputs for all supported regular expression constructs.
Unit Tests:
tests/test_regexp_dcg.pl — Core DCG engine matching tests.tests/test_regexp_tree.pl — Rational Tree Automaton engine tests.tests/test_international.pl — Multilingual character tests (French, Greek, Chinese, Emoji, Klingon).tests/test_regexp_ast.pl — Regex parser and AST construction tests.tests/test_re_token.pl — Regex tokenization (re_token//1), metacharacter, and character class tests.tests/test_exports_match.pl — Module export interface consistency tests across all engine implementations.Testing Requirements:
Run the test suite with:
make test
Drawing inspiration from finite state machine compilers like Ragel and Kleene algebra theory, Prolog is uniquely suited to evolve this regular expression engine beyond string matching into an algebraic reasoning and state machine synthesis tool:
Algebraic Reasoning & Set Operations:
Induction & Shortest Regular Expression Synthesis:
Brzozowski & Antimirov Derivatives:
The Ragel Connection (State Machine Compilation & Embedded Actions):
The regular expression syntax and semantics supported by this library are inspired by Python 3.14 regular expressions (re):
Prolog
96.9%
Makefile
3.1%