Logo Search packages:      
Sourcecode: faucc version File versions

scope.c

/* $Id: scope.c,v 1.65 2009-01-27 15:40:22 potyra Exp $ 
 *
 * Copyright (C) 2007-2009 FAUcc 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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "setup.h"
#include "declaration.h"
#include "stmt.h"
#include "scope.h"
#include "cc1.h"

static struct declaration *dion_current;
struct scope *scope_current;


static int
_scope_lookup_enum(
        struct scope *scope,
        const char *name,
        struct declaration **dorp
)
{
      struct declaration *dion;

      assert(scope->type == SCOPE_ENUM);

      for (dion = scope->declaration_first; ; dion = dion->next) {
            if (! dion) {
                  return -1;
            }
            if (declaration_name_get(dion)
             && strcmp(declaration_name_get(dion), name) == 0) {
                  *dorp = dion;
                  return TYPE_ENUM;
            }
      }
}

static int
_scope_lookup(
        struct scope *scope,
        const char *name,
        struct declaration **dorp
)
{
        struct declaration *dion;

        for (dion = scope->declaration_first; ; dion = dion->next) {
                if (! dion) {
                        /* Not Found */
                        return -1;
                }
            if (dion->type_name
             && dion->type_name->type == TYPE_ENUM
             && dion->type_name->scope) {
                  int ret;

                  ret = _scope_lookup_enum(
                              dion->type_name->scope, name,
                              dorp);
                  if (0 <= ret) {
                        return ret;
                  }
            }
            if (declaration_name_get(dion)
             && strcmp(declaration_name_get(dion), name) == 0) {
                  *dorp = dion;
                  if (scope->type == SCOPE_ENUM) {
                        return TYPE_ENUM;
                  } else {
                        return dion->storage;
                  }
            }
        }
}

int
_scope_lookup_structunionenum(
      struct scope *scope,
      enum type_type type,
      const char *name,
      struct type **tsp
)
{
      struct declaration *dion;

      assert(type == TYPE_STRUCT
          || type == TYPE_UNION);

        for (dion = scope->declaration_first; ; dion = dion->next) {
                if (! dion) {
                        /* Not Found */
                        return -1;
                }
            if (dion->type_name
             && dion->type_name->type == type
             && dion->type_name->identifier
             && strcmp(dion->type_name->identifier, name) == 0
             && dion->type_name->scope) {
                  *tsp = dion->type_name;
                  return 0;
            }
      }
}

static void
_scope_add(struct declaration *d)
{
      d->prev = scope_current->declaration_last;
      d->next = NULL;
      if (d->prev) {
            d->prev->next = d;
      } else {
            scope_current->declaration_first = d;
      }
      scope_current->declaration_last = d;
}

static void
_scope_enter(void)
{
      struct scope *s;

      s = malloc(sizeof(*s));
      assert(s);

      memset(s, 0, sizeof(*s));

      s->prev = scope_current->child_last;
      s->next = NULL;
      if (s->prev) {
            s->prev->next = s;
      } else {
            scope_current->child_first = s;
      }
      scope_current->child_last = s;

      s->parent = scope_current;

      scope_current = s;
}

static void
_scope_leave(void)
{
      scope_current = scope_current->parent;
}

int
scope_lookup_one(
      struct scope *scope,
      const char *name,
      struct declaration **dorp
)
{
      assert(scope);

      return _scope_lookup(scope, name, dorp);
}

int
scope_lookup(
      struct scope *scope,
      const char *name,
      struct declaration **dorp
)
{
        struct scope *s;
        int ret;

      s = scope;

again:      ;
      ret = _scope_lookup(s, name, dorp);
      if (0 <= ret) {
            return ret;
      }

      switch (s->type) {
      case SCOPE_NONE:
            assert(0);

      case SCOPE_GLOBAL:
            /*
             * Nothing more to search...
             */
            return -1;

      case SCOPE_FUNCTION:
            /*
             * Next step: look in parameter list.
             */
            assert(s->function);

            s = type_parameter_get(s->function->type_name);
            assert(s);
            goto again;

      case SCOPE_PARAMETER:
            /*
             * Next step: look in parent list.
             */
            s = s->parent;
            goto again;

      case SCOPE_BLOCK:
            /*
             * Next step: look in upper block / function.
             */
            s = s->parent;
            assert(s->type == SCOPE_BLOCK
                || s->type == SCOPE_FUNCTION);
            goto again;

      case SCOPE_STRUCT:
      case SCOPE_UNION:
      case SCOPE_ENUM:
            /*
             * Next step: look in upper block / function / global list.
             */
            s = s->parent;
            goto again;

      default:
            assert(0);
      }
}

int
scope_lookup_current(
      const char *name,
      struct declaration **dorp
)
{
      return scope_lookup(scope_current, name, dorp);
}

int
scope_lookup_structunionenum(
      struct scope *scope,
      enum type_type type,
      const char *name,
      struct type **tsp
)
{
      struct scope *s;
      int ret;

      assert(type == TYPE_STRUCT
          || type == TYPE_UNION);

      for (s = scope; ; s = s->parent) {
            if (! s) {
                  return -1;
            }
            ret = _scope_lookup_structunionenum(s, type, name, tsp);
            if (0 <= ret) {
                  return ret;
            }
      }
}

static void
_scope_structunionenum_begin(
      const char *identifier,
      enum type_type ttype,
      enum scope_type stype
)
{
      struct declaration *dion;

      if (dion_current) {
            _scope_leave();
      }

      dion = declaration_identifier(NULL);
      dion->type_name = type_new();
      dion->type_name->type = ttype;
      dion->type_name->identifier = identifier;

      if (dion_current) {
            /* Prepend to current struct definition. */
            dion->prev = dion_current->prev;
            dion->next = dion_current;
      } else {
            /* Append to declaration list. */
            dion->prev = scope_current->declaration_last;
            dion->next = NULL;
      }
      if (dion->prev) {
            dion->prev->next = dion;
      } else {
            scope_current->declaration_first = dion;
      }
      if (dion->next) {
            dion->next->prev = dion;
      } else {
            scope_current->declaration_last = dion;
      }

      dion_current = dion;
      _scope_enter();
      scope_current->type = stype;

      dion_current->type_name->scope = scope_current;
}

static void
_scope_structunionenum_end(void)
{
      _scope_leave();
      dion_current = dion_current->next;

      if (dion_current) {
            scope_current = dion_current->type_name->scope;
      }
}

void
scope_struct_begin(const char *identifier)
{
      _scope_structunionenum_begin(identifier, TYPE_STRUCT, SCOPE_STRUCT);
}

void
scope_struct_end(void)
{
      _scope_structunionenum_end();
}

void
scope_union_begin(const char *identifier)
{
      _scope_structunionenum_begin(identifier, TYPE_UNION, SCOPE_UNION);
}

void
scope_union_end(void)
{
      _scope_structunionenum_end();
}

void
scope_enum_begin(const char *identifier)
{
      _scope_structunionenum_begin(identifier, TYPE_ENUM, SCOPE_ENUM);
}

void
scope_enum_add(const char *identifier, unsigned int val)
{
      struct declaration *dion;

      dion = declaration_identifier(identifier);
      dion->type_name = type_int();
      declaration_initializer_set(dion, expr_integer(val));

      dion->prev = scope_current->declaration_last;
      dion->next = NULL;
      if (dion->prev) {
            dion->prev->next = dion;
      } else {
            scope_current->declaration_first = dion;
      }
      scope_current->declaration_last = dion;
}

void
scope_enum_end(void)
{
      _scope_structunionenum_end();
}

void
scope_parameter_begin(void)
{
      _scope_enter();

      scope_current->type = SCOPE_PARAMETER;
}

void
scope_parameter_end(
      struct declaration *first,
      struct declaration *last
)
{
      scope_current->declaration_first = first;
      scope_current->declaration_last = last;

      _scope_leave();
}

void
scope_block_begin(void)
{
      _scope_enter();

      scope_current->type = SCOPE_BLOCK;
}

void
scope_block_end(struct stmt *s)
{
      s->scope = scope_current;

      _scope_leave();
}

void
scope_function_begin(struct type *ts, struct declaration *dion)
{
      assert(scope_current->parent == NULL);

      dion->type_name = type_add_user(dion->type_name, ts);

      _scope_add(dion);

      _scope_enter();

      scope_current->type = SCOPE_FUNCTION;
      scope_current->function = dion;
}

struct label *
scope_function_label_get(const char *identifier)
{
      struct scope *s;
      struct label *l;

      for (s = scope_current; s->type == SCOPE_BLOCK; s = s->parent) {
      }

      for (l = s->label_first; ; l = l->next) {
            if (! l) {
                  l = label_new(identifier);

                  l->prev = s->label_last;
                  l->next = NULL;
                  if (l->prev) {
                        l->prev->next = l;
                  } else {
                        s->label_first = l;
                  }
                  s->label_last = l;

                  return l;
            }
            if (strcmp(l->identifier, identifier) == 0) {
                  return l;
            }
      }
}

void
scope_function_end(struct stmt *s)
{
      scope_block_end(s);

      assert(scope_current->parent == NULL);

      scope_current->declaration_last->stmt = s;
}

void
scope_declaration_prepend_first(
      struct scope *scope,
      struct declaration *nd
)
{
      nd->prev = NULL;
      nd->next = scope->declaration_first;

      scope->declaration_first = nd;
      if (nd->next) {
            nd->next->prev = nd;
      } else {
            scope->declaration_last = nd;
      }
}

void
scope_declaration_prepend(
      struct scope *scope,
      struct declaration *od,
      struct declaration *nd
)
{
      assert(od);

      nd->prev = od->prev;
      nd->next = od;
      if (nd->prev) {
            nd->prev->next = nd;
      } else {
            scope->declaration_first = nd;
      }
      nd->next->prev = nd;
}

void
scope_declaration_append(struct scope *scope, struct declaration *dion)
{
      /*
       * Fix definitions of int8_t, uint8_t, ..., uint64_t.
       */
      if (dion->storage == STORAGE_TYPEDEF
       && dion->identifier) {
            if (strcmp(dion->identifier, "int8_t") == 0) {
                  if (dion->type_name != type_int8()) {
                        fprintf(stderr, "%s: Fixing declaration of int8_t.\n",
                                    progname);
                        dion->type_name = type_int8();
                  }
            } else if (strcmp(dion->identifier, "uint8_t") == 0) {
                  if (dion->type_name != type_uint8()) {
                        fprintf(stderr, "%s: Fixing declaration of uint8_t.\n",
                                    progname);
                        dion->type_name = type_uint8();
                  }
            } else if (strcmp(dion->identifier, "int16_t") == 0) {
                  if (dion->type_name != type_int16()) {
                        fprintf(stderr, "%s: Fixing declaration of int16_t.\n",
                                    progname);
                        dion->type_name = type_int16();
                  }
            } else if (strcmp(dion->identifier, "uint16_t") == 0) {
                  if (dion->type_name != type_uint16()) {
                        fprintf(stderr, "%s: Fixing declaration of uint16_t.\n",
                                    progname);
                        dion->type_name = type_uint16();
                  }
            } else if (strcmp(dion->identifier, "int32_t") == 0) {
                  if (dion->type_name != type_int32()) {
                        fprintf(stderr, "%s: Fixing declaration of int32_t.\n",
                                    progname);
                        dion->type_name = type_int32();
                  }
            } else if (strcmp(dion->identifier, "uint32_t") == 0) {
                  if (dion->type_name != type_uint32()) {
                        fprintf(stderr, "%s: Fixing declaration of uint32_t.\n",
                                    progname);
                        dion->type_name = type_uint32();
                  }
            } else if (strcmp(dion->identifier, "int64_t") == 0) {
                  if (dion->type_name != type_int64()) {
                        fprintf(stderr, "%s: Fixing declaration of int64_t.\n",
                                    progname);
                        dion->type_name = type_int64();
                  }
            } else if (strcmp(dion->identifier, "uint64_t") == 0) {
                  if (dion->type_name != type_uint64()) {
                        fprintf(stderr, "%s: Fixing declaration of uint64_t.\n",
                                    progname);
                        dion->type_name = type_uint64();
                  }
            }
      }

      /*
       * Append to declaration list.
       */
      dion->prev = scope->declaration_last;
      dion->next = NULL;
      if (dion->prev) {
            dion->prev->next = dion;
      } else {
            scope->declaration_first = dion;
      }
      scope->declaration_last = dion;
}

void
scope_asm_add(unsigned int len, const char *code)
{
      struct declaration *dion;

      dion = declaration_new();
      dion->storage = STORAGE_ASM;
      dion->code = code;

      scope_declaration_append(scope_current, dion);
}

void
scope_file_begin(void)
{
      scope_current = malloc(sizeof(*scope_current));
      assert(scope_current);

      memset(scope_current, 0, sizeof(*scope_current));

      scope_current->type = SCOPE_GLOBAL;
}

void
scope_file_end(struct scope **sp)
{
      assert(scope_current->parent == NULL);

      *sp = scope_current;
}

Generated by  Doxygen 1.6.0   Back to index