A device tree compiler in Crystal that stands in for dtc in the Linux and U-Boot builds, so
the BQ2 seed needs neither flex nor bison. It writes the same DTB as dtc 1.7, byte for byte.
make ... DTC=/path/to/cleave-dtc
It takes dtc's options: -O dtb, -o, -b, -i, -@, -L, -R, -S, -p, -a, -d,
-H, -s, -f, -v. -W and -E are accepted and ignored, because dtc's warnings are
lint and don't change the output. Only DTS input and DTB output are supported. --trace
prints every parser pass.
How it parses
It uses the progressive multipass pattern from
crystal-robots (docs/PARSER.md), with the
engine in src/cleave/glyph_parser.cr:
- Lexing (
src/cleave/dts.cr). Each token becomes one glyph. The lexer keeps dtc's start conditions: a name is read only where a statement starts, and bytes are read two hex digits at a time inside[ ]. It counts parentheses, so<and>delimit cells outside them and compare inside them. - Reduction. Each pass applies the first rule in
Dts::GRAMMARthat matches anywhere, to every match. The rules come in priority order:- expressions, by C precedence;
- cell lists and byte strings;
- the delete statements;
- properties;
- nodes, innermost first, since a node reduces only once its body is all properties and subnodes;
- top-level definitions;
- the source,
⏹.
- Building (
src/cleave/dtc.cr). The reduced tree is turned into dtc's live tree with dtc's semantics:- merges into earlier definitions;
- deleted entries kept in place, so a later merge can revive them;
- labels added to the front of the list;
fragment@Nfor references in a plugin.
- Checks. Only the dtc checks that change the output are run, in dtc's order:
- duplicate names;
- redundant
nameproperties; - explicit phandles;
- phandle and path references;
/omit-if-no-ref/;__symbols__(giving every labelled node a phandle);__fixups__and__local_fixups__.
- Writing. The DTB is written as version 17. Property names share strings by suffix, as in dtc's string table.
Checked
- Fixtures.
spec/dtc_spec.crcompares against blobs from dtc 1.7.2, covering expressions,/bits/, byte strings, labels, phandle and path references, merges, deletes,/omit-if-no-ref/,/memreserve/,-@,-R,-p,-a, and an overlay with fixups. - Linux 6.12 (
v6.12.49-ti-arm64-r56). The 266 DTBs and overlays that kbuild made for arm64 are identical to the in-tree dtc's (1.7.0) output. Each run used kbuild's own preprocessed input and flags. - U-Boot 2025.07. The BeagleY-AI R5 DTBs are identical, with U-Boot's
-a 0x8.