Skip to content

Hammer Quick Reference

mdowell-rr edited this page Aug 25, 2026 · 16 revisions

Cheat sheet of every Hammer function and macro used in this wiki's examples, organized by category. Links jump to the page where each one is explained.


Macros (from glue.h)

Parser Definition

Macro Expands To Docs
H_RULE(name, def) HParser *name = def; Hammer Fundamentals
H_ARULE(name, def) HParser *name = h_action(def, act_##name, NULL); NTP: Hex Preprocessing
H_VRULE(name, def) HParser *name = h_attr_bool(def, validate_##name, NULL); Hammer Fundamentals
H_VARULE(name, def) Validation after action: h_attr_bool(h_action(def, act_##name, NULL), validate_##name, NULL) -
H_AVRULE(name, def) Validation before action: h_action(h_attr_bool(def, validate_##name, NULL), act_##name, NULL) -

Parser Definition with User Data

Macro Expands To
H_ADRULE(name, def, data) h_action(def, act_##name, data)
H_VDRULE(name, def, data) h_attr_bool(def, validate_##name, data)
H_VADRULE(name, def, data) Validation after action, both receive data
H_AVDRULE(name, def, data) Validation before action, both receive data

Semantic-action / validation helpers

Macro Purpose Docs
H_ACT_APPLY(myaction, paction, ...) Define myaction as a wrapper that calls parameterized action paction(__VA_ARGS__, p, user_data) -
H_VALIDATE_APPLY(myvalidation, pvalidation, ...) Define myvalidation as a wrapper that calls parameterized predicate pvalidation(__VA_ARGS__, p, user_data) -

Token Construction (for use inside action functions)

Macro Purpose Docs
H_ALLOC(TYP) Allocate TYP from p->arena ((TYP *)h_arena_malloc(p->arena, sizeof(TYP)))
H_MAKE(TYP, VAL) Create a token of custom type TT_##TYP. Requires TT_<type> constant ≥ TT_USER -
H_MAKE_SEQ() Creates an empty HParsedToken sequence NTP: Hex Preprocessing
H_MAKE_SEQN(N) Create empty TT_SEQUENCE with expected capacity N -
H_MAKE_BYTES(ptr, len) Create TT_BYTES token -
H_MAKE_SINT(val) Create TT_SINT token -
H_MAKE_UINT(val) Creates an HParsedToken with an unsigned int value NTP: Hex Preprocessing
H_MAKE_DOUBLE(val) Create TT_DOUBLE token -
H_MAKE_FLOAT(val) Create TT_FLOAT token -

Assertions / casts / indexing

Macro Purpose Docs
h_assert_type(T, tok) Assert tok->token_type == T and return tok (expression) -
H_ASSERT(TYP, tok) Assert custom token type TT_##TYP -
H_ASSERT_SEQ(tok) Assert TT_SEQUENCE -
H_ASSERT_BYTES(tok) Assert TT_BYTES -
H_ASSERT_SINT(tok) Assert TT_SINT -
H_ASSERT_UINT(tok) Assert TT_UINT -
H_ASSERT_DOUBLE(tok) Assert TT_DOUBLE -
H_ASSERT_FLOAT(tok) Assert TT_FLOAT -
H_CAST(TYP, tok) Assert Custom type TT_##TYP, then return (TYP*)tok->token_data.user -
H_CAST_SEQ(tok) Assert sequence, then return tok->token_data.seq -
H_CAST_BYTES(tok) Assert bytes, then return tok->token_data.bytes -
H_CAST_SINT(tok) Assert sint, then return tok->token_data.sint -
H_CAST_UINT(tok) Assert uint, then return tok->token_data.uint -
H_CAST_DOUBLE(tok) Assert double, then return tok->token_data.dbl -
H_CAST_FLOAT(tok) Assert float, then return tok->token_data.flt -
H_INDEX_TOKEN(seq, ...) Nested index access via h_seq_index_path. Terminates path with -1 internally -
H_INDEX(TYP, seq, ...) H_CAST(TYP, H_INDEX_TOKEN(seq, ...)) Nested sequence access -
H_INDEX_SEQ(seq, ...) Nested access returning sequence pointer -
H_INDEX_BYTES(seq, ...) Nested access returning .bytes -
H_INDEX_SINT(seq, ...) Nested access returning .sint -
H_INDEX_UINT(seq, ...) Nested access returning .uint -
H_INDEX_DOUBLE(seq, ...) Nested access returning .dbl -
H_INDEX_FLOAT(seq, ...) Nested access returning .flt -
H_FIELD_TOKEN(...) Like H_INDEX_TOKEN but uses p->ast. For action functions -
H_FIELD(TYP, ...) Like H_INDEX but uses p->ast. For action functions -
H_FIELD_SEQ(...) Like H_INDEX_SEQ but uses p->ast -
H_FIELD_BYTES(...) Like H_INDEX_BYTES but uses p->ast -
H_FIELD_SINT(...) Like H_INDEX_SINT but uses p->ast -
H_FIELD_UINT(...) Like H_INDEX_UINT but uses p->ast -
H_FIELD_DOUBLE(...) Like H_INDEX_DOUBLE but uses p->ast -
H_FIELD_FLOAT(...) Like H_INDEX_FLOAT but uses p->ast -

Parser constructor convenience macros (hammer.h)

Macro Purpose Example Usage
h_literal("str") Literal byte-string parser for string literals (expands to h_token((uint8_t*)s, sizeof(s)-1)) -
h_drop_from(seq, ...) Convenience wrapper for h_drop_from_ that auto-terminates the index list with -1 -

Endianness flags (hammer.h)

Constant Meaning
BYTE_BIG_ENDIAN / BYTE_LITTLE_ENDIAN Byte order
BIT_BIG_ENDIAN / BIT_LITTLE_ENDIAN Bit order within bytes

Data Type Parsers

Function Bits Signed Example Usage
h_bits(n, signed) n configurable Parses into a 64-bit integer token; use n <= 64 to preserve value. NTP: Header - LI (2 bits), VN (3 bits), Mode (3 bits)
h_bytes(len) len*8 - TT_BYTES
h_int8() 8 yes NTP: Header - Poll, Precision
h_uint8() 8 no NTP: Header - Stratum
h_int16() 16 yes NTP: Data Fields - Root Delay/Dispersion halves
h_uint16() 16 no NTP: Extensions - Extension length
h_int32() 32 yes -
h_uint32() 32 no NTP: Data Fields - Reference ID, timestamp halves, Key ID
h_int64() 64 yes NTP: Extensions - Message Digest
h_uint64() 64 no -
h_float16() 16 yes -
h_float32() 32 yes -
h_float64() 64 yes -

Combinators

Sequencing and Repetition

Function Description Example Usage
h_sequence(a, b, ..., NULL) Parse a, b, ... in order; result is a TT_SEQUENCE NTP: Header
h_many(p) Parse p zero or more times; result is a TT_SEQUENCE NTP: Extensions
h_many1(p) Parse p one or more times; result is a TT_SEQUENCE DNS: Body
h_many_cap(p, n) Parse p zero or more times up till n; result is a TT_SEQUENCE
h_many1_cap(p, n) Parse p one or more times up till n; result is a TT_SEQUENCE
h_repeat_n(p, n) Parse p exactly n times; result is a TT_SEQUENCE NTP: Hex Preprocessing
h_sepBy(p, sep) Zero or more p separated by sep; results of sep are discarded -
h_sepBy1(p, sep) One or more p separated by sep; results of sep are discarded -
h_permutation(a, b, ..., NULL) Match all parsers exactly once in any order; returns results in argument order -

h_many1 vs h_sequence + h_many: h_many1(p) and h_sequence(p, h_many(p), NULL) match the same inputs, but their results differ. h_many1 returns a flat sequence, while the h_sequence version returns a sequence whose second element is another sequence.

Choice and Filtering

Function Description Example Usage
h_choice(a, b, ..., NULL) Try parsers in order; return first success NTP: Assembling
h_dispatch(discriminator, opcode_map, default) Given a dictionary-like OpcodeMap of parsers linked with opcodes, apply the parser linked to the opcode read by the discriminator parser; apply default parser if opcode doesn't match to a parser. -
h_optional(p) Apply p; if it fails, succeed with TT_NONE instead. Never fails -
h_int_range(p, lo, hi) Parse with p; fail if value is outside [lo, hi] NTP: Header
h_float_range(p, lo, hi) Parse with p; fail if value is outside [lo, hi] -
h_attr_bool(p, pred, data) Parse with p; fail unless pred(result, data) returns true Hammer Fundamentals
h_butnot(p1, p2) Succeed if p1 matches and p2 fails, or p1's result is longer than p2's -
h_difference(p1, p2) Succeed if p1 matches and p2 fails, or p1's result is at least as long as p2's -
h_xor(p1, p2) Succeed if exactly one of p1 or p2 succeeds -

Structural (Discarding Results)

Function Description Example Usage
h_left(a, b) Parse a then b; return only a's result NTP: Assembling
h_right(a, b) Parse a then b; return only b's result -
h_middle(a, b, c) Parse a, b, c in order; return only b's result -
h_ignore(p) Parse with p; on success, return a NULL AST (elided from surrounding sequences) -
h_whitespace(p) Consume and discard leading whitespace (space, tab, newline, etc.), then apply p -
h_drop_from_(seq, i0, i1, ..., -1) Parse a sequence but drop specified indices from the result sequence -

Token and Character Matching

Function Description Example Usage
h_token(str, len) Match the literal byte string str of length len. Result is TT_BYTES -
h_ch(c) Match a single specific byte c. Result is TT_UINT -
h_ch_range(lo, hi) Match one byte in [lo, hi]. Result is TT_UINT NTP: Hex Preprocessing
h_in(charset, len) Match one byte if it appears in charset. Result is TT_UINT -
h_not_in(charset, len) Match one byte if it does not appear in charset. Result is TT_UINT -

Lookahead

Function Description
h_and(p) Apply p without consuming input. Succeeds if p succeeds. AST is NULL
h_not(p) Apply p without consuming input. Succeeds if p fails. AST is NULL
h_end_p() Assert end of input (zero-width). NTP: Assembling

Special

Function Description
h_epsilon_p() Consume no input, always succeed. Result is non-NULL but AST is NULL
h_nothing_p() Always fail. Useful for stubbing out parsers during development

Data-Dependent & State/Continuation

Function Description Example Usage
h_put_value(p, name) Parse with p; store result under name NTP: Extensions
h_get_value(name) Retrieve store value name without freeing -
h_free_value(name) Retrieve stored value and free the binding NTP: Extensions
h_length_value(len_p, val_p) Parse len_p for a count n, then parse val_p n times NTP: Extensions
h_action(p, fn, data) Parse with p; transform result with C function fn NTP: Extensions
h_action_stash(p, fn, data, collection) Parse with p; wait to transform result with C function fn until h_action_apply with collection is called -
h_action_apply(p, collection) Parse with p; run matching stashed actions within p that share collection -
h_bind(p, k, env) Monadic bind for HParsers. Run p and call result x. Then run k(x, env). Fail if p fails or if k(env, x) fails or if k(env,x) is NULL. -
h_indirect() Create a forward-declared parser for recursive grammars Hammer Fundamentals
h_bind_indirect(indirect, p) Bind a parser created with h_indirect() to an actual parser p Hammer Fundamentals
Function Description Docs
h_skip(nbits) Skip nbits bits; AST is NULL -
h_seek(offset_bits, whence) Seek in bits (SEEK_SET/SEEK_CUR/SEEK_END); returns new position as TT_UINT -
h_tell() Current bit position; returns TT_UINT DNS: Body
h_with_endianness(flags, p) Run p under endianness flags (BYTE_* OR BIT_*) -

Runtime API

One shot parsing

Function Description Docs
h_parse(parser, data, len) Run parser on data; returns HParseResult * or NULL Hammer Fundamentals

Incremental parsing

Function Description Docs
h_parse_start(p) Start an incremental parse; returns HSuspendedParser* or NULL if unsupported. Only supported by some backends -
h_parse_chunk(s, input, length) Feed a chunk; returns true if parser s is done (needs no more input) -
h_parse_finish(s) Finish incremental parse; signals end-of-input; returns HParseResult* or NULL -

Lifecycle

Function Description Docs
h_parse_result_free(result) Free an HParseResult when done DNS: Assembling
h_parser_free(parser) Free an HParser dynamically -
h_parse_diagnostic_free(diagnostic) Free an HParseDiagnostic when done -

Debug printing / formatting

Function Description Docs
h_pprint(stream, tok, indent, delta) Pretty-print an HParsedToken tree to a FILE * stream Running and Testing
h_pprint_ast_indexed(stream, tok, indent) Pretty-print an HParsedToken abstract syntax tree with proper indexing -
h_pprintln(stream, tok) Pretty-print an HParsedToken to the given output. Print a trailing newline -
h_write_result_unamb(tok) Pretty-print an HParsedToken in an unambiguous form. Returns string that must be freed -

Error reporting

Add #include <hammer/hammer_auto_source.h> after #include <hammer/hammer.h> to change all the combinators to macros that wrap the source location for the error report.

Function Description Docs
h_parse_debug(parser, input, length, diagnostic, show) like h_parse(), but collects an HParseDiagnostic diagnostic to collect failure info, when show is set to true it will print to stdout -
h_parse_diagnostic_fprint(stream, diagnostic) Print a diagnostic to the given output. -
h_parse_diagnostic_fprint_with_input combines h_parse_debug and h_parse_diagnostic_fprint -
h_parse_diagnostic_free(diagnostic) Free the given HParseDiagnostic -
h_parser_set_label(p,label) apply label to parser p to show as the name in debug diagnostics -
h_parser_set_error_message(p, message) apply message to parser p to show as the error in debug diagnostics -
h_parse_diagnostic_trace_fprint(diagnostic, length) Print a diagnostic's complete execution trace. -

Parse Result Types

HParsedToken is a discriminated union. The token_type field tells you which member of token_data is valid. See Hammer Fundamentals for a full explanation.

HTokenType Value Union Field Description
TT_INVALID 0 - Invalid token types (internal / sentinel)
TT_NONE 1 - No value (used by h_optional on failure, h_end_p, etc.)
TT_BYTES 2 .bytes Byte string with .token (pointer) and .len (length)
TT_SINT 4 .sint Signed integer (int64_t)
TT_UINT 8 .uint Unsigned integer (uint64_t)
TT_DOUBLE 12 .dbl Double-precision float
TT_FLOAT 13 .flt Single-precision float
TT_SEQUENCE 16 .seq Sequence of HParsedToken * elements
TT_ERR 32 - Error token type (backend / internal use)
TT_USER 64+ .user User-defined type (void *). See User-Defined Token Types

Parse Tree Manipulation (for Action Functions)

Common struct fileds

API Description Example Usage
result->ast Root HParsedToken * of a parse result NTP: Hex Preprocessing
token->token_type The HTokenType discriminant indicating which union field is valid Hammer Fundamentals
token->token_data.bytes.token Pointer to byte data in a TT_BYTES token -
token->token_data.bytes.len Length of byte data in a TT_BYTES token -
token->token_data.sint Signed integer value of a token -
token->token_data.uint Unsigned integer value of a token NTP: Hex Preprocessing
token->token_data.dbl Value for TT_DOUBLE -
token->token_data.flt Value for TT_FLOAT -
token->token_data.seq->used Number of elements in a sequence token NTP: Hex Preprocessing
token->token_data.seq->elements[i] Element pointers (raw) -

Sequence helpers

API Description Example Usage
h_seq_len(tok) Length of a sequence token -
h_seq_elements(tok) Pointer to element array -
h_seq_index(tok, i) Get element at index i of a sequence NTP: Hex Preprocessing
h_seq_index_path(tok, i, ..., -1) Nested access by index path -
h_seq_snoc(seq_tok, elem_tok) Append one element to a sequence NTP: Hex Preprocessing
h_seq_append(seq_tok, other_seq_tok) Append many elements from another sequence -
h_seq_remove(seq_tok, n) Remove n elements from a sequence -
h_seq_flatten(arena, tok) Flatten nested sequences into a single sequence -

Token constructors

API Description Example Usage
h_make(arena, type, value) Generic constructor -
h_make_seq(arena) Empty sequence -
h_make_seqn(arena, n) Empty sequence with expected size -
h_make_bytes(arena, ptr, len) Bytes token -
h_make_sint(arena, val) Signed int token -
h_make_uint(arena, val) Unsigned int token -
h_make_double(arena, val) Double token -
h_make_float(arena, val) Float token -

Built-in Semantic Actions

Hammer provides ready-made action functions you can pass to h_action or use with H_ARULE. These save you from writing common transformations by hand.

Function Description
h_act_first Given a sequence, return its first element. Asserts the result is a sequence with >= 1 element
h_act_second Given a sequence, return its second element. Asserts >= 2 elements
h_act_last Given a sequence, return its last element. Asserts >= 1 element
h_act_index(i, p, data) Given a sequence, return element at index i. Returns NULL AST if out of bounds
h_act_flatten Recursively flatten nested sequences into a single top-level sequence
h_act_ignore Replace the AST with NULL (action equivalent of the h_ignore combinator)

Example

H_RULE(pair, h_sequence(h_uint8(), h_uint16(), NULL));

HParser *first_only = h_action(pair, h_act_first, NULL);
HParser *second_only = h_action(pair, h_act_second, NULL);

Backend Management

Function Description Example Usage
h_is_backend_available(backend) Returns 1 if backend is available, else 0 -
h_get_default_backend() Returns default backend (currently PB_PACKRAT) -
h_get_default_backend_vtable() Returns default backend vtable -
h_query_backend_by_name(name) Lookup backend enum by name; returns PB_INVALID if unknown -
h_get_backend_with_params_by_name("lalr(1)") Parse backend specification string into a backend+params config -
h_copy_backend_with_params(cfg) Copy a backend+params config -
h_free_backend_with_params(cfg) Free a backend+params config -
h_get_name_for_backend(backend) Get backend name (const; do not free) -
h_get_name_for_backend_with_params(cfg) Get backend name string (allocated; must free) -
h_get_descriptive_text_for_backend(backend) Get descriptive text (const; do not free) -
h_get_descriptive_text_for_backend_with_params(cfg) Get descriptive text (allocated; must free) -

Parser Compilation

Function Description Example Usage
h_compile(parser, backend, params) Compile a parser for a backend -
h_compile_for_backend_with_params(parser, cfg) Compile using a backend config created from name+params -

Bit Writer

Function Description Example Usage
h_bit_writer_new(mm__) Create a new HBitWriter -
h_bit_writer_put(w, data, nbits) Append nbits bits of data into writer -
h_bit_writer_get_buffer(w, &len) Get internal buffer pointer + length (bytes) -
h_bit_writer_free(w) Free writer and buffer -

Benchmarking

Function Description Example Usage
h_benchmark(parser, testcases) Run parser against testcases across backends; returns results -
h_benchmark_report(stream, results) Print a report -

Result Buffer Printers

Low-level helpers used by some printers / registry functions.

Function Description Example Usage
h_append_buf(buf, input, len) Append string data to a result buffer -
h_append_buf_c(buf, char) Append one char -
h_append_buf_formatted(buf, fmt, ...) Append printf-style formatted text -

Token Type Registry

Function Description Example Usage
h_allocate_token_type(name) Allocate a new token type id -
h_allocate_token_new(name, unamb_sub, pprint) Allocate token type with print functions -
h_get_token_type_number(name) Lookup token type id by name -
h_get_token_type_name(token_type) Lookup token type name by id -

Allocators

Function Description Example Usage
h_sloballoc(mem, size) Allocator backed by a fixed caller-provided memory region -

Common Patterns

Fixed-size field

H_RULE(my_field, h_uint32());

Sub-byte field with validation

H_RULE(my_field, h_int_range(h_bits(3, false), 0, 7));

Fixed-point number (split into halves)

H_RULE(my_field, h_sequence(h_int16(), h_int16(), NULL));

Length-prefixed variable data

HParsedToken *adjust_len(const HParseResult *p, void *user_data) {
    return H_MAKE_UINT(p->ast->uint - HEADER_SIZE);
}

H_RULE(my_field,
       h_sequence(
           h_put_value(h_uint16(), "len"),
           h_length_value(h_action(h_free_value("len"), adjust_len, NULL), h_uint8()),
           NULL));

Zero-or-more repetition

H_RULE(many_fields, h_many(single_field));

Ordered alternatives with end-of-input

H_RULE(type_a, h_sequence(fields_a, h_end_p(), NULL));
H_RULE(type_b, h_sequence(fields_b, h_end_p(), NULL));
HParser *parser = h_left(h_choice(type_a, type_b, NULL), h_end_p());

Quoted string (discard delimiters)

H_RULE(quoted, h_middle(h_ch('"'), h_many1(h_ch_range(0x20, 0x7E)), h_ch('"')));

Recursive grammar

HParser *expr = h_indirect();
H_RULE(atom, h_choice(number, expr, NULL));
h_bind_indirect(expr, h_middle(h_ch('('), atom, h_ch(')')));

Back to Home

Clone this wiki locally