123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621 |
- /**
- * Copyright (C) 2011 Anders Sundman <anders@4zm.org>
- *
- * 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 <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <stddef.h>
- #include "util.h"
- #include "spec_syntax.h"
- // Forward declarations
- int sp_parse();
- extern FILE* sp_in;
- // Parse the input file and set up type_root and instance_root.
- // Return 0 on success.
- int spec_import(FILE* input) {
- // Parse the input to build a type hierarchy
- sp_in = input;
- if (sp_parse()) {
- printf("Syntax Error: Specification not imported\n");
- goto error;
- }
- // Check for missing definitions
- type_t* partial = tt_contains_partial_types();
- if (partial) {
- printf("Error: Incomplete declaration '%s' in specification.\n",
- partial->composite_extras->name);
- goto error;
- }
- // Make sure we have a root type defined
- if (type_root == NULL) {
- printf("Error: No root type '.' found in specification.\n");
- goto error;
- }
- // Create the instance tree
- instance_root = make_instance_tree(type_root);
- printf("Specification sucessfully imported.\n");
- return 0;
- error:
- clear_instance_tree();
- tt_clear();
- return 1;
- }
- // The primitive Byte type
- type_t byte_type = {
- .type_category = BYTE_TYPE,
- .composite_extras = NULL,
- };
- // The primitive Bit type
- type_t bit_type = {
- .type_category = BIT_TYPE,
- .composite_extras = 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) {
- type_t* t = malloc(sizeof(type_t));
- t->type_category = COMPOSITE_TYPE;
- t->composite_extras = (composite_type_extras_t*)
- malloc(sizeof(composite_type_extras_t));
- if (name)
- t->composite_extras->name = name;
- else
- t->composite_extras->name = NULL; // Anonymous type
- t->composite_extras->fields = NULL;
- return t;
- }
- // Free a composite type. This function will also free it's fields.
- void free_composite_type(type_t* t) {
- // Free the fields
- field_list_t* iter = t->composite_extras->fields;
- while (iter) {
- field_list_t* tmp = iter;
- iter = iter->next_;
- free_field(tmp->field);
- free(tmp);
- }
- // Free the type data
- free(t->composite_extras->name);
- free(t->composite_extras);
- free(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) {
- field_t* f = (field_t*) malloc(sizeof(field_t));
- f->name = name; // NULL for fillers
- f->type = type;
- f->length = length;
- return f;
- }
- // Free the memory used by a field.
- void free_field(field_t* field) {
- if (field == NULL)
- return;
- free(field->name);
- free(field);
- }
- // Add a field to an existing list of fields or, if the field_list
- // parameter is NULL, create a new field list. 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) {
- // Create the list node
- field_list_t* flist = (field_list_t*) malloc(sizeof(field_list_t));
- flist->field = field;
- flist->next_ = NULL;
- // Create the list or append to the end
- if (field_list != NULL) {
- field_list_t* it = field_list;
- while(it->next_)
- it = it->next_;
- it->next_ = flist;
- }
- else {
- field_list = flist; // Won't effect the inarg
- }
- // Return the start of the list
- return field_list;
- }
- // Search the field list for a field with the given name
- field_t* get_field(field_list_t* field_list, const char* name) {
- if (name == NULL || field_list == NULL)
- return NULL;
- field_list_t* it = field_list;
- while(it) {
- field_t* f = it->field;
- if (f && f->name && strcmp(f->name, name) == 0)
- return f;
- it = it->next_;
- }
- // Not found
- return NULL;
- }
- // 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.
- type_table_t* type_table = NULL;
- // The root type of the type hierarchy
- type_t* type_root = NULL;
- // Internal functions for allocating and freeing type table list nodes.
- type_table_t* tt_make_node_(type_t* t);
- void tt_free_node_(type_table_t* tt);
- // Clear the type table - freeing the memory used by the table and by
- // all the types.
- void tt_clear() {
- // Reset the root
- type_root = NULL;
- // Free all types and the table itself
- type_table_t* it = type_table;
- while(it) {
- type_table_t* next = it->next_;
- free_composite_type(it->type);
- tt_free_node_(it);
- it = next;
- };
- type_table = NULL;
- }
- // Add a type to the type table.
- type_t* tt_add_type(type_t* t) {
- if (type_table == NULL) {
- type_table = tt_make_node_(t);
- }
- else {
- type_table_t* it = type_table;
- while(it->next_)
- it = it->next_;
- it->next_ = tt_make_node_(t);
- }
- return 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) {
- if (type_name == NULL)
- return NULL;
- type_table_t* it = type_table;
- while(it) {
- // Anonymous types (name == NULL) will never match
- if (it->type->composite_extras->name &&
- strcmp(type_name, it->type->composite_extras->name) == 0)
- return it->type; // Type was found!
- it = it->next_;
- }
- // Not found
- return NULL;
- }
- // 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_table_t* it = type_table;
- while(it) {
- if (it->type->composite_extras->decl_status == PARTIAL_DECL)
- return it->type;
- it = it->next_;
- }
- return NULL;
- }
- // Allocate a new list entry for the type table
- type_table_t* tt_make_node_(type_t* t) {
- type_table_t* tt = malloc(sizeof(type_table_t));
- tt->type = t;
- tt->next_ = NULL;
- return tt;
- }
- // Free a type table list entry (this won't free the type)
- void tt_free_node_(type_table_t* tt) {
- free(tt);
- }
- // The global variable representing the root instance; it is an
- // instanciation of the '.' type.
- instance_t* instance_root = NULL;
- // Forward decls of internal functions used during creation and
- // destruction of the instance tree.
- void clear_instance_tree_(instance_t* root);
- void make_instance_(instance_t* root,
- size_t* obytes, size_t* obits,
- size_t* sbytes, size_t* sbits);
- instance_t* make_byte_instance_(field_t* field, size_t* obytes, size_t* obits);
- instance_t* make_bit_instance_(field_t* field, size_t* obytes, size_t* obits);
- instance_t* make_composite_instance_(field_t* field,
- size_t* obytes, size_t* obits);
- instance_list_t* append_instance_(instance_list_t** end_ptr,
- instance_t* new_field);
- // Create an instance tree matching the type tree starting at
- // type_root. The global instance tree is constructed with type_root '.'.
- instance_t* make_instance_tree(type_t* type_root) {
- instance_t* root = malloc(sizeof(instance_t));
- root->offset_bytes = 0;
- root->offset_bits = 0;
- root->size_bytes = 0;
- root->size_bits = 0;
- root->field = make_field(strdup("."), type_root, 1);
- root->fields = NULL;
- size_t obytes = 0;
- size_t obits = 0;
- make_instance_(root, &obytes, &obits,
- &(root->size_bytes), &(root->size_bits));
- return root;
- }
- // Clear the global instance tree. Free it and set instance_root NULL
- void clear_instance_tree() {
- if (instance_root == NULL)
- return;
- clear_instance_tree_(instance_root);
- instance_root = NULL;
- }
- /* 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) {
- if (name == NULL)
- return NULL;
- return get_instance_child_n(inst, name, strlen(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) {
- if (inst == NULL || name == NULL || nlen == 0)
- return NULL;
- instance_list_t* iter = inst->fields;
- while(iter) {
- field_t* f = iter->instance->field;
- // Make sure the field has a name (isn't anaonymous) before comparing.
- if (f && f->name &&
- strlen(f->name) == nlen &&
- strncmp(f->name, name, nlen) == 0)
- return iter->instance;
- iter = iter->next_;
- }
- return NULL;
- }
- /**
- * 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) {
- const char* lastpath;
- instance_t* inst;
- // Parse the path up to the last instance
- if (parse_partial_spec_path(path, &lastpath, &inst) != 0)
- return NULL;
- // Find and return the leaf node
- return get_instance_child(inst, lastpath);
- }
- /**
- * 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) {
- // Check input. Paths start with '.'
- if (path == NULL || path[0] != '.')
- return 1;
- instance_t* inst = instance_root;
- const char* remaining_path = path + 1;
- char* tok_end;
- while((tok_end = strchr(remaining_path, '.')) != NULL) {
- // There is still a part of the path before the last '.'
- ptrdiff_t tok_name = tok_end - remaining_path;
- if (tok_name <= 0)
- return 1;
- inst = get_instance_child_n(inst, remaining_path, (size_t)tok_name);
- // Exit early (error in ancestor path)
- if (inst == NULL)
- return 1;
- // Remove the token and the '.' from the start of remaining string
- remaining_path = tok_end + 1;
- }
- // Set the output arguments
- if (parent_end != NULL)
- *parent_end = remaining_path;
- if (parent_inst != NULL)
- *parent_inst = inst;
- return 0;
- }
- // Count the number of fields in the instance
- int instance_fields_count(instance_t* inst) {
- if (inst == NULL)
- return 0;
- int count = 0;
- instance_list_t* it = inst->fields;
- while (it) {
- ++count;
- it = it->next_;
- }
- return count;
- }
- void clear_instance_tree_(instance_t* root) {
- instance_list_t* iter = root->fields;
- while (iter) {
- instance_list_t* tmp = iter->next_;
- clear_instance_tree_(iter->instance);
- free(iter);
- iter = tmp;
- }
- free(root);
- }
- void make_instance_(instance_t* root,
- size_t* obytes, size_t* obits,
- size_t* sbytes, size_t* sbits) {
- // Pointers to the matching type field and instance field beign processed.
- field_list_t* tf_iter = root->field->type->composite_extras->fields;
- instance_list_t* if_iter = root->fields;
- // Iterate over all the type fields and add matching instance fields.
- while(tf_iter) {
- field_t* f = tf_iter->field;
- // Create the child sub-tree or instance.
- instance_t* child;
- // Byte
- if (f->type == &byte_type) {
- child = make_byte_instance_(f, obytes, obits);
- }
- // Bit
- else if (f->type == &bit_type) {
- child = make_bit_instance_(f, obytes, obits);
- }
- // Composite type
- else {
- child = make_composite_instance_(f, obytes, obits);
- child->size_bytes = 0;
- child->size_bits = 0;
- make_instance_(child, obytes, obits,
- &(child->size_bytes), &(child->size_bits));
- // Update size with bits % 8
- child->size_bytes =
- child->size_bytes * f->length +
- (child->size_bits * f->length) / 8;
- child->size_bits = (child->size_bits * f->length) % 8;
- }
- // Add the new instance or instance tree, to the root instance
- // field list.
- if_iter = if_iter == NULL ?
- append_instance_(&(root->fields), child) :
- append_instance_(&(if_iter->next_), child);
- // Note that we are changing the value of the input parameters here
- // this is part of the 'return value' of the function. Wrap the
- // bit size mod 8.
- *sbytes = *sbytes + child->size_bytes + (*sbits + child->size_bits) / 8;
- *sbits = (*sbits + child->size_bits) % 8;
- tf_iter = tf_iter->next_;
- }
- }
- instance_t* make_byte_instance_(field_t* field, size_t* obytes, size_t* obits) {
- instance_t* i = malloc(sizeof(instance_t));
- i->field = field;
- i->fields = NULL;
- i->offset_bytes = *obytes;
- i->offset_bits = *obits;
- i->size_bytes = field->length;
- i->size_bits = 0;
- *obytes += i->size_bytes;
- // *obits += 0;
- return i;
- }
- instance_t* make_bit_instance_(field_t* field, size_t* obytes, size_t* obits) {
- instance_t* i = malloc(sizeof(instance_t));
- i->field = field;
- i->fields = NULL;
- i->offset_bytes = *obytes;
- i->offset_bits = *obits;
- // Bits % 8, overflow in bytes field
- i->size_bytes = field->length / 8;
- i->size_bits = field->length % 8;
- *obytes += i->size_bytes + (*obits + i->size_bits) / 8;
- *obits = (*obits + i->size_bits) % 8;
- return i;
- }
- instance_t* make_composite_instance_(field_t* field,
- size_t* obytes, size_t* obits) {
- instance_t* i = malloc(sizeof(instance_t));
- i->field = field;
- i->fields = NULL;
- i->offset_bytes = *obytes;
- i->offset_bits = *obits;
- // The size will be updated later, after recusion into all child fields.
- i->size_bytes = 0;
- i->size_bits = 0;
- return i;
- }
- instance_list_t* append_instance_(instance_list_t** end_ptr,
- instance_t* new_field) {
- instance_list_t* il = (instance_list_t*) malloc(sizeof(instance_list_t));
- il->instance = new_field;
- il->next_ = NULL;
- *end_ptr = il;
- return il;
- }
- // Forward declaration
- void print_instance_tree_(instance_t* i, int indent);
- void print_instance_(instance_t* i);
- void print_instance_tree() {
- if (instance_root == NULL) {
- printf("No specification loaded.\n");
- return;
- }
- printf("[%zu, %zu] [%zu, %zu] -- . (root)\n",
- instance_root->offset_bytes,
- instance_root->offset_bits,
- instance_root->size_bytes,
- instance_root->size_bits);
- print_instance_tree_(instance_root, 1);
- }
- void print_instance_tree_(instance_t* root, int indent) {
- // For each field of the root instance
- instance_list_t* il = root->fields;
- while(il) {
- // Indent
- int count = (indent - 1) * 2;
- while(count--)
- printf(" ");
- printf("+- ");
- // Print instance field
- instance_t* inst = il->instance;
- print_instance_(inst);
- if (inst->field->type->composite_extras != NULL)
- print_instance_tree_(inst, indent + 1);
- il = il->next_;
- }
- }
- void print_instance_(instance_t* i) {
- if (i->field->type == &byte_type) {
- printf("[%zu, %zu] [%zu, %zu] -- Byte[%zu] %s\n",
- i->offset_bytes,
- i->offset_bits,
- i->size_bytes,
- i->size_bits,
- i->field->length,
- i->field->name);
- }
- else if (i->field->type == &bit_type) {
- printf("[%zu, %zu] [%zu, %zu] -- Bit[%zu] %s\n",
- i->offset_bytes,
- i->offset_bits,
- i->size_bytes,
- i->size_bits,
- i->field->length,
- i->field->name);
- }
- else {
- printf("[%zu, %zu] [%zu, %zu] -- %s[%zu] %s\n",
- i->offset_bytes,
- i->offset_bits,
- i->size_bytes,
- i->size_bits,
- i->field->type->composite_extras->name,
- i->field->length,
- i->field->name);
- }
- }
|