# Code Generation Overview
`synta-codegen --lang c` generates complete C code (both headers and
implementations) from ASN.1 schemas, providing production-ready
encoder/decoder functions that work with the libcsynta C API.
## The Pipeline
1. Parse one or more ASN.1 schema files.
2. Topologically sort all type definitions (leaf types first).
3. Emit a C header (`.h`) with type definitions, forward declarations, and
function prototypes.
4. Emit a C implementation (`.c`) with full `TypeName_decode`,
`TypeName_encode`, and `TypeName_free` implementations.
Every function calls libcsynta directly; the generated `.c` file has no other
dependencies beyond `<string.h>` and `<stdlib.h>`.
## Quick Start
```bash
# Generate C header to stdout
synta-codegen --lang c schema.asn1
# Generate header to a file
synta-codegen --lang c -o types.h schema.asn1
# Generate implementation file (--impl names the header to #include)
synta-codegen --lang c --impl types.h -o types.c schema.asn1
# Specify a custom path for synta.h inside the generated header
synta-codegen --lang c --header-path /usr/local/include/synta.h -o types.h schema.asn1
```
### Compile and Link
```bash
cc -c types.c -o types.o $(pkg-config --cflags csynta)
cc myapp.c types.o -o myapp $(pkg-config --libs csynta)
```
Without pkg-config:
```bash
cc -I/path/to/synta/include -c types.c -o types.o
cc myapp.c types.o -o myapp -L/path/to/synta/lib -lcsynta
```
The generated code requires a C99-capable compiler (`-std=c99` or later).
## What You Get
### Header File (.h)
- Type definitions (structs, enums, unions) in topological order
- Forward declarations
- Function prototypes (`TypeName_decode`, `TypeName_encode`, `TypeName_free`)
- Optional helper functions (`TypeName_init`, `TypeName_validate`,
`TypeName_print`) when `--with-helpers` is active
- C/C++ compatibility (`extern "C"` guards)
Every generated header begins with:
```c
#include <stdint.h>
#include <stdbool.h>
#include "synta.h" /* or the path given by --header-path */
```
### Implementation File (.c)
- Full `TypeName_decode` implementations using `synta_decoder_*` functions
- Full `TypeName_encode` implementations using `synta_encoder_*` functions
- `TypeName_free` with NULL-safe cleanup of every heap-allocated field
- Error propagation on every libcsynta call
## Generated Function Signatures
For each type `TypeName` the generator emits at minimum three functions:
```c,ignore
/* Decode from DER/BER into an already-allocated struct */
SyntaErrorCode TypeName_decode(SyntaDecoder *decoder, TypeName *out);
/* Encode a struct to DER/BER via an existing encoder */
SyntaErrorCode TypeName_encode(SyntaEncoder *encoder, const TypeName *value);
/* Release all heap resources owned by the struct.
Does NOT free the struct itself. */
void TypeName_free(TypeName *value);
```
With `--with-helpers`, three additional static inline helpers appear in the
header (see [Helper Functions](build-integration.md)).
With `--arena`, an additional `TypeName_decode_arena()` variant is generated
(see [Arena Allocator](arena-allocator.md)).
## Full End-to-End Example
### Input: ASN.1 Schema
```asn1
Certificate DEFINITIONS ::= BEGIN
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
END
```
### Generated Header (certificate.h, excerpt)
```c
#ifndef CERTIFICATE_H
#define CERTIFICATE_H
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "synta.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct AlgorithmIdentifier AlgorithmIdentifier;
struct AlgorithmIdentifier {
SyntaObjectIdentifier* algorithm;
bool has_parameters;
SyntaOctetString* parameters;
};
SyntaErrorCode algorithm_identifier_decode(SyntaDecoder* decoder,
AlgorithmIdentifier* out);
SyntaErrorCode algorithm_identifier_encode(SyntaEncoder* encoder,
const AlgorithmIdentifier* value);
void algorithm_identifier_free(AlgorithmIdentifier* value);
#ifdef __cplusplus
}
#endif
#endif /* CERTIFICATE_H */
```
### Usage in Application Code
```c
#include "certificate.h"
int main(void) {
AlgorithmIdentifier alg_id;
algorithm_identifier_init(&alg_id); /* zeroes all fields */
alg_id.algorithm = synta_oid_from_string("1.2.840.113549.1.1.11");
alg_id.has_parameters = false;
SyntaEncoder *encoder = synta_encoder_new(SyntaEncoding_Der);
SyntaErrorCode err = algorithm_identifier_encode(encoder, &alg_id);
if (err != SyntaErrorCode_Success) {
fprintf(stderr, "Encode error: %s\n", synta_error_message(err));
return 1;
}
SyntaByteArray encoded = {0};
synta_encoder_finish(encoder, &encoded);
/* encoder consumed by synta_encoder_finish; do not free it */
/* Decode back */
SyntaDecoder *decoder = synta_decoder_new(encoded.data, encoded.len,
SyntaEncoding_Der);
AlgorithmIdentifier decoded;
algorithm_identifier_init(&decoded);
err = algorithm_identifier_decode(decoder, &decoded);
/* Cleanup */
algorithm_identifier_free(&alg_id);
algorithm_identifier_free(&decoded);
synta_decoder_free(decoder);
synta_byte_array_free(&encoded);
return 0;
}
```
## Code Generation Statistics
From the X.509 certificate example schema (10 types):
- **Header file**: approximately 192 lines
- **Implementation file**: approximately 665 lines
- **Total**: approximately 857 lines of production-ready C code
## Supported Features
### Fully Supported
- SEQUENCE / SET types with full encode/decode
- SEQUENCE OF / SET OF with dynamic array allocation
- CHOICE types as discriminated unions (tag enum + union)
- INTEGER types including named numbers (enums) and constrained ranges
- BIT STRING (dedicated `SyntaBitString` struct)
- OBJECT IDENTIFIER
- OCTET STRING and string variants (UTF8String, PrintableString, IA5String)
- Time types (UTCTime, GeneralizedTime)
- Optional fields with presence flags
- Type references between defined types
- Error handling and cleanup
### Partial Support
- `[N] EXPLICIT` tagged fields — fully supported for primitive and TypeRef
inner types; anonymous inline SEQUENCE/SET inside an EXPLICIT tag is not
yet supported
- `[N] IMPLICIT` tagged fields — fully supported for structural inner types
(SEQUENCE, SET, SEQUENCE OF, SET OF, and TypeRefs that resolve to them)
### Not Yet Implemented
- Complex constraint validation in generated code (see [Constraints](constraints.md))
## Multi-Module Projects
For schemas that import types from other schemas, use `--output-dir` with
`--emit both`:
```bash
synta-codegen --lang c --emit both --output-dir ./generated/ \
base.asn1 extension.asn1
```
Each module produces a `<stem>.h` and `<stem>.c` pair in topological order.
Import references resolve to the corresponding module header.
Use `--check-imports` to validate inter-module imports without generating
output:
```bash
synta-codegen --check-imports base.asn1 extension.asn1
```