#ifndef SPEC_SYNTAX__H
#define SPEC_SYNTAX__H
/**
* Copyright (C) 2011 Anders Sundman <[email protected]>
*
* This file is part of mfterm.
*
* mfterm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* mfterm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with mfterm. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
typedef enum {
COMPOSITE_TYPE,
BYTE_TYPE,
BIT_TYPE,
} type_category_t;
typedef enum {
PARTIAL_DECL,
COMPLETE_DECL,
} type_decl_status_t;
typedef struct type_t type_t;
typedef struct field_t field_t;
typedef struct field_list_t field_list_t;
typedef struct composite_type_extras_t composite_type_extras_t;
typedef struct type_table_t type_table_t;
typedef struct instance_t instance_t;
typedef struct instance_list_t instance_list_t;
// Parse the input file and set up type_root and instance_root.
// Return 0 on success.
int spec_import(FILE* input);
/**
* A struct representing a data type in the specification
* language. There are two primitive types, Bit and Bytte. All other
* types are user defined and use the composite_extras field to
* express the type details.
*
* The primitive types are allocated statically (constants), while all
* the composite types are allocated dynamically.
*/
struct type_t {
type_category_t type_category;
composite_type_extras_t* composite_extras;
};
// The primitive type instances
extern type_t byte_type;
extern type_t bit_type;
/**
* A composite type is made up of an ordered list of fields. A field
* is a named use of another type as an array. A field array of length
* 1 can be treated without the array syntax in the language; but is
* represented like all other fields.
*/
struct field_t {
char* name; // Field name
type_t* type;
size_t length;
};
/**
* Type representing the ordered list of fields in a composite type.
*/
struct field_list_t {
field_t* field;
field_list_t* next_;
};
/**
* This structure represents the content of a user defined type. It
* holds the name and the fields of the type.
*
* The type also has a flag to indicate if it has been fully
* declared. The specification language allows the use of types before
* they have been declared. Once the complete specification has been
* parsed, all types must be declared.
*/
struct composite_type_extras_t {
char* name; // Type name
type_decl_status_t decl_status;
field_list_t* fields; // All fields of the type or NULL.
};
// Allocate and return a composite type instance. The type will assume
// ownership of the heap allocated name.
type_t* make_composite_type(char* name);
// Free a composite type. This function will also free it's fields.
void free_composite_type(type_t* t);
// Allocate a new field with the given parameters. Anonymous '-'
// filler fields use NULL as name. The field will assume ownership of
// the heap allocated name.
field_t* make_field(char* name, type_t* type, size_t length);
// Free the memory used by a field.
void free_field(field_t* field);
// Add a field to an existing list of fields. The order of fields is
// significant and this function will append the field to the end of
// the field_list.
field_list_t* append_field(field_list_t* field_list, field_t* field);
// Search the field list for a field with the given name
field_t* get_field(field_list_t* field_list, const char* name);
/**
* A 'table' of all the types in the language. This is part of the
* output from the parsing process. The table is actually a list and
* operations are typically O(n^2); but since there will probably
* never be more than 50 types, this should be ok.
*/
struct type_table_t {
type_t* type;
type_table_t* next_;
};
// The global instance of the type table. If there isn't any, the
// variable will be NULL. All the type table operations (tt_) operate
// on this global variable.
extern type_table_t* type_table;
// The root type of the type hierarchy
extern type_t* type_root;
// Clear the type table - freeing the memory used by the table and by
// all the types.
void tt_clear();
// Add a type to the type table.
type_t* tt_add_type(type_t* t);
// Search the type table for a type with the given name. The first
// type found will be returned. If no type is found, NULL is returned.
type_t* tt_get_type(const char* type_name);
// Check if there are any partially declared types in the type
// table. Return a pointer to the first incomplete type or NULL if
// none exists.
type_t* tt_contains_partial_types();
/**
* Type representing instances of types in the spec language. The same
* type can be instantiated several times in different spec types and
* fields. The instances map agains type fields and thus contains a
* length field.
*
* The size field is inclusive of the instance and all it's child
* instances. The bit size field will be < 8; larger bit fields in the
* type spec will be included in the byte field.
*/
struct instance_t {
size_t offset_bytes;
size_t offset_bits;
size_t size_bytes;
size_t size_bits;
field_t* field;
instance_list_t* fields;
};
/**
* Type representing the ordered list of instance fields in a
* composite type instance.
*/
struct instance_list_t {
instance_t* instance;
instance_list_t* next_;
};
// The global variable representing the root instance; it is an
// instanciation of the '.' type.
extern instance_t* instance_root;
// Create an instance tree matching the type tree starting at
// root_type. The global instance tree is constructed with root_type '.'.
instance_t* make_instance_tree(type_t* root_type);
// Clear the global instance tree. Free it and set instance_tree NULL
void clear_instance_tree();
// Print a representation of the instance hierarchy
void print_instance_tree();
/**
* Get the child instance with a given name. Only look to children,
* not grand children. If no child with the given name exists, return
* null.
*/
instance_t* get_instance_child(instance_t* inst, const char* name);
/**
* Like get_instance_child(inst, name), but name does not have to be
* null terminated. Instead the length of the name string is given by
* the last argument.
*/
instance_t* get_instance_child_n(instance_t* inst, const char* name, size_t nlen);
/**
* Parse a specification path of the form '.fu.bar.baz' and return the
* instance pointed to by baz. In case the path doesn't point to a
* loaded instance, return NULL. */
instance_t* parse_spec_path(const char* path);
/**
* Parse the path to produce a parent section and an instance that
* points to the head of the parent.
*
* The format is .fu.bar.ba(z). Where .fu.bar.ba is the path, fu, bar
* and baz are nested fields. The function should return parent_end
* pointing into path to the point after the last '.', i.e. to the 'b'
* in the last 'ba'. parent_inst will point to bar.
*
* The function returns 0 on success.
*/
int parse_partial_spec_path(const char* path,
const char** parent_end,
instance_t** parent_inst);
// Return the number of fields the instance has. 0 if inst is NULL.
int instance_fields_count(instance_t* inst);
#endif