Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

sigs_and_comps.c

/* $Id: sigs_and_comps.c,v 1.23 2009-01-27 17:06:42 potyra Exp $ 
 *
 * Copyright (C) 2005-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "compiler.h"
#include "config.h"
#include "memory.h"
#include "list.h"
#include "log.h"
#include "sigs_and_comps.h"
#include "umutil.h"

/* meta description of signal types and components */

struct sig_type {
      struct list_node node;
      struct list_header name;
      const char *bridge;
      const char *type;
      int noconfig;
      int connect_component;
      int bus;
};

struct component {
      struct list_node node;
      const char *name;
      struct list_header generics;
      struct list_header port;
      struct list_header simsetup;
      struct list_header internal_sigs;
      struct list_header fault_sigs;
      struct list_header hefkg_sigs;

      int index;
};

enum direction {DIR_NULL, DIR_IN, DIR_OUT, DIR_INOUT};

struct sig_enum {
      struct list_node node;
      const char *name;
      const char *type;
      enum direction dir;
      struct list_header init;
};

struct list_header      types;
struct list_header      components;

enum tokens {T_ERROR, T_EOF, T_STRING, T_COLON, T_SEMICOLON, T_LBRACE, T_RBRACE, T_COMMA, T_EQUAL};
static char token_value[128];

static enum tokens
get_token(FILE *fhdl, int *line)
{
      int c;
      int i = 0;
      int state;

      state = 1;
      while (state) {
            c = fgetc(fhdl);
            switch(c) {
                  case EOF:
                        return T_EOF;
                  case '#':
                        while (1) {
                              c = fgetc(fhdl);
                              if (c == EOF) return T_EOF;
                              else if (c == '\n') {
                                    (*line)++;
                                    break;
                              }
                        }
                        break;
                  case ' ':
                  case '\t':
                        break;
                  case '\n':
                        (*line)++;
                        break;
                  case ';':
                        return T_SEMICOLON;
                  case ',':
                        return T_COMMA;
                  case ':':
                        return T_COLON;
                  case '{':
                        return T_LBRACE;
                  case '}':
                        return T_RBRACE;
                  case '=':
                        return T_EQUAL;
                  default:
                        state = 0;
                        break;
            }
      }
      if (c == '"') {
            int start = *line;

            while (1) {
                  c = fgetc(fhdl);
                  if (c == EOF) {
                        logit(LOG_ERROR, "unfinished string starting at line %d\n", start);
                        return T_ERROR;
                  } else if (c == '"') {
                        token_value[i] = 0;
                        return T_STRING;
                  }
                  token_value[i++] = c;
                  if (sizeof(token_value) <= i) {
                        logit(LOG_ERROR, "string starting at line %d to long for buffer\n", start);
                        return T_ERROR;
                  }
            }
      }
      while (('0' <= c && c <= '9')
                  || ('a' <= c && c <= 'z')
                  || ('A' <= c && c <= 'Z')
                  || c == '(' || c == ')'
                  || c == '_' || c == '-') {
            token_value[i++] = c;
            if (sizeof(token_value) <= i) {
                  logit(LOG_ERROR, "string starting at line %d to long for buffer\n", *line);
                  return T_ERROR;
            }
            c = fgetc(fhdl);
      }
      c = ungetc(c, fhdl);
      assert(c != EOF);
      if (i == 0) return T_ERROR;
      token_value[i] = 0;
      return T_STRING;
}

const char *
tok2string(enum tokens tok, int flag)
{
      switch(tok) {
            case T_ERROR:
                  return "illegal character";
            case T_EOF:
                  return "end of file";
            case T_COMMA:
                  return "','";
            case T_COLON:
                  return "':'";
            case T_SEMICOLON:
                  return "';'";
            case T_LBRACE:
                  return "'{'";
            case T_RBRACE:
                  return "'}'";
            case T_EQUAL:
                  return "'='";
            case T_STRING:
                  if (flag) {
                        return token_value;
                  } else {
                        return "identifier";
                  }
            default:
                  assert(0);
      }

      return NULL;
}

static int
check_token(enum tokens tok, enum tokens expected, int line, int term)
{
      if (tok == expected) return 0;
      if (term) {
            logit(LOG_ERROR, "found %s in line %d, expected %s\n",
                        tok2string(tok, 1), line, tok2string(expected, 0));
            exit(1);
      }
      return 1;
}

void
sac_init(const char *filename)
{
      FILE *fhdl;
      int state;
      int line = 1;

      struct component *curr_comp = NULL;
      struct sig_type *curr_type = NULL;
      struct sig_enum *curr_element = NULL;
      struct list_header *curr_list = NULL;
      const char **store_string = NULL;

      /* parse description of FAUmachine signals and components */

      list_init(&types);
      list_init(&components);
      if (filename == NULL) {
            filename = buildpath(FAUMDATADIR, "sigs_and_comps.spec");
      }
      fhdl = fopen(filename, "r");
      if (fhdl == NULL) {
            fprintf(stderr, "failed to open %s: %s\n",
                        filename, strerror(errno));
            exit(1);
      }

      state = 0;
      while (0 <= state) {
            enum tokens tok;

            tok = get_token(fhdl, &line);
#if 0
            fprintf(stderr, "state = %d, got token %s\n", state, tok2string(tok, 1));
#endif
            switch (state) {
                  case 0:
                        if (tok == T_STRING) {
                              if (strcmp(token_value, "signal") == 0) {
                                    state = 1;
                                    curr_type = (struct sig_type *)malloc(sizeof(struct sig_type));
                                    assert(curr_type);
                                    list_push(&types, curr_type);
                                    list_init(&curr_type->name);
                                    curr_type->bridge = NULL;
                                    curr_type->noconfig = 0;
                                    curr_type->connect_component = 0;
                                    curr_type->bus = 0;

                              } else if (strcmp(token_value, "component") == 0) {
                                    state = 100;
                                    curr_comp = (struct component *)malloc(sizeof(struct component));
                                    assert(curr_comp);
                                    list_push(&components, curr_comp);
                                    curr_comp->name = NULL;
                                    list_init(&curr_comp->generics);
                                    list_init(&curr_comp->port);
                                    list_init(&curr_comp->simsetup);
                                    list_init(&curr_comp->internal_sigs);
                                    list_init(&curr_comp->hefkg_sigs);
                                    list_init(&curr_comp->fault_sigs);
                              } else {
                                    logit(LOG_ERROR, "expecting keyword 'component' or 'type', found '%s' in line %d\n",
                                                token_value, line);
                                    exit(1);
                              }
                        } else if (tok == T_EOF) {
                              state = -1;
                        } else {
                              check_token(tok, T_STRING, line, 1);
                        }
                        break;
                  case 1:
                        check_token(tok, T_STRING, line, 1);
                        list_new_dnode(&curr_type->name, mem_new_string(token_value));
                        state = 2;
                        break;
                  case 2:
                        if (tok == T_COMMA) { state = 1; }
                        else if (tok == T_LBRACE) { state = 3; }
                        else {
                              logit(LOG_ERROR, "expected ',' or '{', found %s\n", tok2string(tok, 0));
                              exit(1);
                        }
                        break;
                  case 3:
                        if (tok == T_STRING) {
                              if (strcmp(token_value, "bridge") == 0) {
                                    state = 4;
                                    store_string = &curr_type->bridge;
                              } else if (strcmp(token_value, "type") == 0) {
                                    state = 4;
                                    store_string = &curr_type->type;
                              } else if (strcmp(token_value, "noconfig") == 0) {
                                    curr_type->noconfig = 1;
                                    state = 5;
                              } else if (strcmp(token_value, "bus") == 0) {
                                    curr_type->bus = 1;
                                    state = 5;
                              } else if (strcmp(token_value, "connect_component") == 0) {
                                    curr_type->connect_component = 1;
                                    state = 5;
                              } else {
                                    logit(LOG_ERROR, "illegal keyword '%s' in type definition, line %d\n",
                                                token_value, line);
                                    exit(1);
                              }
                        } else if (tok == T_RBRACE) {
                              state = 0;
                              curr_type = NULL;
                        } else {
                              logit(LOG_ERROR, "expecting end of type definition or keyword, found '%s' in line %d\n",
                                          tok2string(tok, 0), line);
                              exit(1);
                        }
                        break;
                  case 4:
                        if (tok == T_STRING) {
                              *store_string = mem_new_string(token_value);
                              state = 5;
                        } else if (tok == T_COLON) {
                        } else {
                              logit(LOG_ERROR, "expected ':' or string, found '%s' in line %d\n",
                                          tok2string(tok, 0), line);
                              exit(1);
                        }
                        break;
                  case 5:
                        check_token(tok, T_SEMICOLON, line, 1);
                        state = 3;
                        break;
                  case 6:
                        if (tok == T_STRING) {
                              if (strcmp(token_value, "TCP") == 0
                                          || strcmp(token_value, "UDP") == 0) {
                                    curr_type->bridge = mem_new_string(token_value);
                                    state = 5;
                              } else {
                                    logit(LOG_ERROR, "illegal bridge method: %s\n", token_value);
                                    exit(1);
                              }
                        } else if (tok == T_COLON) {
                        } else {
                              logit(LOG_ERROR, "expected ':' or bridge method, found '%s' in line %d\n",
                                          tok2string(tok, 0), line);
                              exit(1);
                        }
                        break;

                  /* handling components */

                  case 100:
                        check_token(tok, T_STRING, line, 1);
                        curr_comp->name = mem_new_string(token_value);
                        state = 101;
                        break;
                  case 101:
                        check_token(tok, T_LBRACE, line, 1);
                        state = 102;
                        break;
                  case 102:
                        if (tok == T_STRING) {
                              if (strcmp(token_value, "generics") == 0) {
                                    state = 103;
                                    curr_list = &curr_comp->generics;
                              } else if (strcmp(token_value, "port") == 0) {
                                    state = 103;
                                    curr_list = &curr_comp->port;
                              } else if (strcmp(token_value, "simsetup") == 0) {
                                    state = 103;
                                    curr_list = &curr_comp->simsetup;
                              } else if (strcmp(token_value, "internal") == 0) {
                                    state = 103;
                                    curr_list = &curr_comp->internal_sigs;
                              } else if (strcmp(token_value, "hefkg") == 0) {
                                    state = 103;
                                    curr_list = &curr_comp->hefkg_sigs;
                              } else if (strcmp(token_value, "fault_injection") == 0) {
                                    state = 103;
                                    curr_list = &curr_comp->fault_sigs;
                              } else {
                                    logit(LOG_ERROR, "unexpect keyword '%s' in component definition at line %d\n",
                                                token_value, line);
                                    exit(1);
                              }
                        } else if (tok == T_RBRACE) {
                              state = 0;
                              curr_comp = NULL;
                        }
                        break;
                  case 103:
                        check_token(tok, T_LBRACE, line, 1);
                        state = 104;
                        break;
                  case 104:
                        if (tok == T_RBRACE) {
                              state = 102;
                              curr_list = NULL;
                        } else if (tok == T_STRING) {
                              curr_element = (struct sig_enum *)malloc(sizeof(struct sig_enum));
                              assert(curr_list);
                              list_push(curr_list, curr_element);
                              curr_element->name = mem_new_string(token_value);
                              curr_element->type = NULL;
                              curr_element->dir = DIR_NULL;
                              list_init(&curr_element->init);
                              state = 105;
                        } else {
                              logit(LOG_ERROR, "expected name of setup element, found %s in line %d\n",
                                          tok2string(tok, 0), line);
                              exit(1);
                        }
                        break;
                  case 105:
                        check_token(tok, T_COLON, line, 1);
                        state = 106;
                        break;
                  case 106:
                        if (tok == T_STRING) {
                              if (strcmp(token_value, "IN") == 0) {
                                    curr_element->dir = DIR_IN;
                              } else if (strcmp(token_value, "OUT") == 0) {
                                    curr_element->dir = DIR_OUT;
                              } else if (strcmp(token_value, "INOUT") == 0) {
                                    curr_element->dir = DIR_INOUT;
                              } else {
                                    curr_element->type = mem_new_string(token_value);
                                    state = 107;
                              }
                        } else if (tok == T_EQUAL) {
                              state = 108;
                        } else {
                              logit(LOG_ERROR, "expected type specifier for setup element in line %d, found %s\n",
                                          line, tok2string(tok, 1));
                              exit(1);
                        }
                        break;
                  case 107:
                        if (tok == T_SEMICOLON) {
                              curr_element = NULL;
                              state = 104;
                        } else if (tok == T_EQUAL) {
                              state = 108;
                        } else {
                              logit(LOG_ERROR, "expected token ';' or '=', found '%s' in line %d\n",
                                          tok2string(tok, 1), line);
                              exit(1);
                        }
                        break;
                  case 108:
                        if (tok == T_SEMICOLON) {
                              curr_element = NULL;
                              state = 104;
                        } else if (tok == T_STRING) {
                              list_new_dnode(&curr_element->init, mem_new_string(token_value));
                              state = 109;
                        } else {
                              logit(LOG_ERROR, "expected initializer or ';', found '%s' in line %d\n",
                                          tok2string(tok, 1), line);
                              exit(1);
                        }
                        break;
                  case 109:
                        if (tok == T_COMMA) {
                              state = 108;
                        } else if (tok == T_SEMICOLON) {
                              state = 104;
                              curr_element = NULL;
                        } else {
                              logit(LOG_ERROR, "expected ',' or ';', found '%s' in line %d\n",
                                          tok2string(tok, 1), line);
                              exit(1);
                        }
                        break;
                  default:
                        assert(0);
            }
      }
      fclose(fhdl);
}

static struct component *
find_component(const char *name)
{
      struct component *comp;

      list_Foreach(&components, comp) {
            if (strcmp(name, comp->name) == 0) break;
      }
      return comp;
}

int
sac_get_component_index(const char *name)
{
      struct component *comp;

      comp = find_component(name);
      assert(comp);
      return comp->index++;
}

void
sac_reset_component_index(void)
{
      struct component *comp;

      list_Foreach(&components, comp) {
            comp->index = 0;
      }
}

int
sac_sig_connect_component(const char *name)
{
      struct sig_type *sig;

      list_Foreach(&types, sig) {
            struct list_dnode *dnode;

            list_Foreach(&sig->name, dnode) {
                  const char *str = (char *)dnode->data;
                  if (strcmp(str, name) == 0) return sig->connect_component;
            }
      }
      assert(0);
      return 0;
}

int
sac_sig_isbus(const char *name)
{
      struct sig_type *sig;

      list_Foreach(&types, sig) {
            struct list_dnode *dnode;

            list_Foreach(&sig->name, dnode) {
                  const char *str = (char *)dnode->data;
                  if (strcmp(str, name) == 0) return sig->bus;
            }
      }
      assert(0);
      return 0;
}

const char *
sac_bridge_config(const char *name)
{
      struct sig_type *sig;

      list_Foreach(&types, sig) {
            struct list_dnode *dnode;

            list_Foreach(&sig->name, dnode) {
                  if (strcmp((const char *)(dnode->data), name) == 0) {
                        break;
                  }
            }
            if (dnode) break;
      }
      if (sig) return sig->bridge;
      fprintf(stderr, "sac: signal type '%s' not found\n", name);
      assert(0);
      return 0;
}

int
sac_component_exists(const char *name)
{
      struct component *comp;

      comp = find_component(name);
      if (comp) return 1;
      return 0;
}

static struct sig_enum *
find_generic(const char *comp_name, const char *generic_name)
{
      struct component *comp;
      struct sig_enum *generic;

      comp = find_component(comp_name);
      if (comp == NULL) return NULL;

      list_Foreach(&comp->generics, generic) {
            if (strcmp(generic->name, generic_name) == 0) break;
      }
      return generic;
}

static struct sig_enum *
find_simsetup(const char *comp_name, const char *simsetup_name)
{
      struct component *comp;
      struct sig_enum *simsetup;

      comp = find_component(comp_name);
      if (comp == NULL) return NULL;

      list_Foreach(&comp->simsetup, simsetup) {
            if (strcmp(simsetup->name, simsetup_name) == 0) break;
      }
      return simsetup;
}

static struct sig_enum *
find_port(const char *comp_name, const char *port_name)
{
      struct component *comp;
      struct sig_enum *port;

      comp = find_component(comp_name);
      if (comp == NULL) return NULL;

      list_Foreach(&comp->port, port) {
            if (strcmp(port->name, port_name) == 0) break;
      }
      return port;
}

static struct sig_enum *
find_fault(const char *comp_name, const char *fault_name)
{
      struct component *comp;
      struct sig_enum *fault;

      comp = find_component(comp_name);
      if (comp == NULL) return NULL;

      list_Foreach(&comp->fault_sigs, fault) {
            if (strcmp(fault->name, fault_name) == 0) break;
      }
      return fault;
}

static struct sig_enum *
find_internal(const char *comp_name, const char *internal_name)
{
      struct component *comp;
      struct sig_enum *internal;

      comp = find_component(comp_name);
      if (comp == NULL) return NULL;

      list_Foreach(&comp->internal_sigs, internal) {
            if (strcmp(internal->name, internal_name) == 0) break;
      }
      return internal;
}

static struct sig_enum *
find_hefkg(const char *comp_name, const char *hefkg_name)
{
      struct component *comp;
      struct sig_enum *hefkg;

      comp = find_component(comp_name);
      if (comp == NULL) return NULL;

      list_Foreach(&comp->hefkg_sigs, hefkg) {
            if (strcmp(hefkg->name, hefkg_name) == 0) break;
      }
      return hefkg;
}

const char *
sac_generic_callback(const char *comp_name, const char *generic_name)
{
      const char *callback_type_name = "use_setup_callback_4_";
      struct sig_enum *generic;
      
      generic = find_generic(comp_name, generic_name);
      if (generic == NULL) {
            fprintf(stderr, "generic '%s' not found in component '%s'\n",
                        generic_name, comp_name);
            assert(0);
      }
      if (strncmp(generic->type, callback_type_name, strlen(callback_type_name)) == 0) {
            return generic->type + strlen(callback_type_name);
      }
      return NULL;
}

struct list_header *
sac_generic_defaults(const char *comp_name, const char *generic_name)
{
      struct sig_enum *generic;
      
      generic = find_generic(comp_name, generic_name);
      assert(generic);
      return &generic->init;
}

void
sac_free_list(struct list_header *list)
{
      while (1) {
            struct list_dnode *dnode;

            dnode = (struct list_dnode *)list_shift(list);
            if (dnode) free(dnode);
            else break;
      }
      list_free(list);
}

struct list_header *
sac_comp_list()
{
      struct list_header *list;
      struct component *comp;

      list = list_new();
      list_Foreach(&components, comp) {
            list_new_dnode(list, const_cast(void *, comp->name));
      }
      return list;
}

struct list_header *
sac_comp_generic_names(const char *comp_name)
{
      struct list_header *list;
      struct sig_enum *generic;
      struct component *comp;

      comp = find_component(comp_name);
      if (! comp) return NULL;

      list = list_new();
      list_Foreach(&comp->generics, generic) {
            list_new_dnode(list, const_cast(void *, generic->name));
      }
      return list;
}

const char *
sac_comp_generic_type(const char *comp_name, const char *generic_name)
{
      struct sig_enum *generic;

      generic = find_generic(comp_name, generic_name);
      assert(generic);
      return generic->type;
}

const char *
sac_comp_generic_first_initializer(const char *comp_name, const char *generic_name)
{
      struct sig_enum *generic;

      generic = find_generic(comp_name, generic_name);
      assert(generic);
      if (generic->init.num) {
            return (const char *)(((struct list_dnode *)(generic->init.first))->data);
      }
      return NULL;
}

struct list_header *
sac_comp_port_names(const char *comp_name)
{
      struct list_header *list;
      struct sig_enum *port;
      struct component *comp;

      comp = find_component(comp_name);
      if (! comp) return NULL;

      list = list_new();
      list_Foreach(&comp->port, port) {
            list_new_dnode(list, const_cast(void *, port->name));
      }
      return list;
}

const char *
sac_comp_port_dir(const char *comp_name, const char *port_name)
{
      struct sig_enum *port;

      port = find_port(comp_name, port_name);
      assert(port);
      switch (port->dir) {
            case DIR_IN:
                  return "IN";
            case DIR_OUT:
                  return "OUT";
            case DIR_INOUT:
                  return "INOUT";
            default:
                  assert(0);
      }
      return NULL;
}

const char *
sac_comp_port_type(const char *comp_name, const char *port_name)
{
      struct sig_enum *port;

      port = find_port(comp_name, port_name);
      assert(port);
      return port->type;
}

struct list_header *
sac_comp_fault_names(const char *comp_name)
{
      struct list_header *list;
      struct sig_enum *port;
      struct component *comp;

      comp = find_component(comp_name);
      if (! comp) return NULL;

      list = list_new();
      list_Foreach(&comp->fault_sigs, port) {
            list_new_dnode(list, const_cast(void *, port->name));
      }
      return list;
}

const char *
sac_comp_fault_type(const char *comp_name, const char *fault_name)
{
      struct sig_enum *fault;

      fault = find_fault(comp_name, fault_name);
      assert(fault);
      return fault->type;
}

struct list_header *
sac_comp_internal_names(const char *comp_name)
{
      struct list_header *list;
      struct sig_enum *port;
      struct component *comp;

      comp = find_component(comp_name);
      if (! comp) return NULL;

      list = list_new();
      list_Foreach(&comp->internal_sigs, port) {
            list_new_dnode(list, const_cast(void *, port->name));
      }
      return list;
}

const char *
sac_comp_internal_type(const char *comp_name, const char *internal_name)
{
      struct sig_enum *internal;

      internal = find_internal(comp_name, internal_name);
      assert(internal);
      return internal->type;
}

struct list_header *
sac_comp_simsetup_names(const char *comp_name)
{
      struct list_header *list;
      struct sig_enum *simsetup;
      struct component *comp;

      comp = find_component(comp_name);
      if (! comp) return NULL;

      list = list_new();
      list_Foreach(&comp->simsetup, simsetup) {
            list_new_dnode(list, const_cast(void *, simsetup->name));
      }
      return list;
}

const char *
sac_comp_simsetup_first_initializer(const char *comp_name, const char *simsetup_name)
{
      struct sig_enum *simsetup;

      simsetup = find_simsetup(comp_name, simsetup_name);
      assert(simsetup);
      if (simsetup->init.num) {
            return (const char *)(((struct list_dnode *)(simsetup->init.first))->data);
      }
      return NULL;
}


struct list_header *
sac_simsetup_defaults(const char *comp_name, const char *simsetup_name)
{
      struct sig_enum *simsetup;
      
      simsetup = find_simsetup(comp_name, simsetup_name);
      assert(simsetup);
      return &simsetup->init;
}

struct list_header *
sac_comp_hefkg_names(const char *comp_name)
{
      struct list_header *list;
      struct sig_enum *port;
      struct component *comp;

      comp = find_component(comp_name);
      if (! comp) return NULL;

      list = list_new();
      list_Foreach(&comp->hefkg_sigs, port) {
            list_new_dnode(list, const_cast(void *, port->name));
      }
      return list;
}

const char *
sac_comp_hefkg_type(const char *comp_name, const char *hefkg_name)
{
      struct sig_enum *hefkg;

      hefkg = find_hefkg(comp_name, hefkg_name);
      assert(hefkg);
      return hefkg->type;
}

struct list_header *
sac_sig_list(void)
{
      struct list_header *list;
      struct sig_type *sig;

      list = list_new();
      list_Foreach(&types, sig) {
            struct list_dnode *dnode;

            list_Foreach(&sig->name, dnode) {
                  list_new_dnode(list, dnode->data);
            }
      }
      return list;
}

Generated by  Doxygen 1.6.0   Back to index