Beispiel #1
0
int main(int argc, char *argv[])
{
    struct definition def;
    enum compile_target target = parse_args(argc, argv);

    /* Add default search paths last, with lowest priority. These are searched
     * after anything specified with -I. */
    add_include_search_path("/usr/include");
    add_include_search_path("/usr/local/include");

    init(input);
    register_builtin_definitions();
    set_compile_target(output, target);

    if (target == TARGET_NONE) {
        preprocess(output);
    } else {
        push_scope(&ns_ident);
        push_scope(&ns_tag);
        push_scope(&ns_label);
        register_builtin_types(&ns_ident);

        do {
            def = parse();
            if (def.symbol && !errors)
                compile(def);
        } while (def.symbol && !errors);

        if (errors)
            error("Aborting because of previous %s.",
                (errors > 1) ? "errors" : "error");

        compile_symbols(
            get_tentative_definitions(&ns_ident));

        if (verbose_level) {
            output_symbols(stdout, &ns_ident);
            output_symbols(stdout, &ns_tag);
            output_symbols(stdout, &ns_label);
        }

        flush();
        pop_scope(&ns_label);
        pop_scope(&ns_tag);
        pop_scope(&ns_ident);
    }

    if (output != stdout)
        fclose(output);

    return errors;
}
Beispiel #2
0
void PSIVisitor::visit_model(IModel *model) {
	fprintf(stdout, "--> visit_model(%p)\n", model);
	IPackage *pkg = model->getGlobalPackage();
	visit_package(pkg);

	ModelImpl *model_i = dynamic_cast<ModelImpl *>(model);
	for (int32_t i=0; i<model->getItems().size(); i++) {
		IBaseItem *it = model->getItems().at(i);
		fprintf(stdout, "-- it=%p %d\n", it, it->getType());

		m_removed = false;
		push_scope(it);
		if (it->getType() == IBaseItem::TypePackage) {
			IPackage *pkg = dynamic_cast<IPackage *>(it);
			visit_package(pkg);
		} else if (it->getType() == IBaseItem::TypeComponent) {
			visit_component(dynamic_cast<IComponent *>(it));
		} else {
			// Really shouldn't be anything else in the global scope
		}
		pop_scope();

		if (m_removed) {
			model_i->remove(it);
			delete it;
			i--;
		}
	}
	fprintf(stdout, "<-- visit_model(%p)\n", model);
}
Beispiel #3
0
PUBLIC type end_rec_type(void)
{
     type p = alloc_type();

     p->x_kind = RECORD;
     p->x_fields = pop_scope();
     return p;
}
Beispiel #4
0
extern "C" XformVar* insert_xform(POETCode* xvar)
{ 
  XformVar* res = curfile->insert_xformDecl(xvar);
  while (tmpScope.size())
       pop_scope(0);
  push_scope(res,true);
  return res;
}
Beispiel #5
0
static PLI_INT32 sys_dumpvars_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
      vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
      vpiHandle argv = vpi_iterate(vpiArgument, callh);
      vpiHandle item;
      s_vpi_value value;
      unsigned depth = 0;

      (void)name; /* Parameter is not used. */

      if (dump_file == 0) {
	    open_dumpfile(callh);
	    if (dump_file == 0) {
		  if (argv) vpi_free_object(argv);
		  return 0;
	    }
      }

      if (install_dumpvars_callback()) {
	    if (argv) vpi_free_object(argv);
	    return 0;
      }

        /* Get the depth if it exists. */
      if (argv) {
	    value.format = vpiIntVal;
	    vpi_get_value(vpi_scan(argv), &value);
	    depth = value.value.integer;
      }
      if (!depth) depth = 10000;

        /* This dumps all the modules in the design if none are given. */
      if (!argv || !(item = vpi_scan(argv))) {
	    argv = vpi_iterate(vpiModule, 0x0);
	    assert(argv);  /* There must be at least one top level module. */
	    item = vpi_scan(argv);
      }

      for ( ; item; item = vpi_scan(argv)) {

	    int dep = draw_scope(item);

	    scan_item(depth, item, 0);
	      /* The scope list must be sorted after we scan an item.  */
	    vcd_names_sort(&lxt_tab);

	    while (dep--) pop_scope();
      }

	/* Most effective compression. */
      if (lxm_optimum_mode == LXM_SPACE) {
	    lt_set_no_interlace(dump_file);
      }

      return 0;
}
struct ast* reach(struct ast* a, struct ast* block) {

  if (a->node_type == N_ARRAY) {

    if (block != NULL) {

      struct ast* arr = (struct ast*) a->left;
      struct opt_block_node* b = (struct opt_block_node*) block;

      // obtengo arreglo a partir de Array
      int arr_size = array_tree_size(arr);

      struct ast* result[arr_size];

      struct ast* ptr = arr;
      int i;
      for (i = (arr_size - 1); i > -1; i--) {
        result[i] = ptr->left;
        ptr = ptr->right;
      };

      // itero sobre array
      for (i = 0; i < arr_size; i++) {
        push_scope();

        // put first arg to scope
        if (b->opt_ids != NULL) {
          put_sym(SYM_VAR, string_value(b->opt_ids->arg), result[i], NULL);
        };

        // eval block stmts
        eval_ast(b->stmts);

        pop_scope();
      }; 

      return a;

    } else {
      block_is_required_error(EACH_ITERATOR);
    };

  } else {
    no_method_error(EACH_ITERATOR, a);
  };  

};
Beispiel #7
0
int main(int argc, char **argv) {
    char *file_to_eval = NULL;
    int replize = argc < 1;
    for(int i = 1; i < argc; i++) {
        if(!strcmp("-f", argv[i]))
            file_to_eval = argv[++i];
        else if(!strcmp("--verbose", argv[i]))
            VERBOSE = true;
        else if(!strcmp("-i", argv[i]))
            replize = true;
    }

    init_alloc_system();
    init_symboltable();
    register_builtin_functions();

    new_var(new_symbol("nil"), (LispObject*)nil);
    new_var(new_symbol("t"), (LispObject*)new_symbol("t"));

    nexception_points++;
    if(setjmp(exception_points[nexception_points - 1]) == 0) {
        eval_file("prelude.l");
        if(file_to_eval)
            eval_file(file_to_eval);
        else
            repl();
    } else {
        fprintf(stderr, "%s", error_string);
        printf("Stack trace:\n");
        for(int i = 0; i < call_stack->size; i++) {
            printf("  ");
            obj_print(vector_getitem(call_stack, i));
            printf("\n");
        }
        while(scopes->size > 1)
            pop_scope();
        while(call_stack->size > 1)
            vector_remove(call_stack, -1);
        if(replize)
            repl();
    }
}
		void 
		_interpreter::flush_scopes(void)
		{
			scope_factory_ptr scop_fact;

			TRACE_ENTRY();
			SERIALIZE_CALL_RECUR(m_lock);

			if(luna::is_globally_initialized()) {

				scop_fact = get_scope_factory();
				if(scop_fact) {

					while(!m_scope_stack.empty()) {
						scop_fact->remove_scope(m_scope_stack.top());
						pop_scope();
					}
				}
			}

			TRACE_EXIT("Return Value: 0x%x", NULL);
		}
Beispiel #9
0
void PSIVisitor::visit_package(IPackage *pkg) {
	std::vector<IBaseItem *>::const_iterator it=pkg->getItems().begin();

	for (int32_t i=0; i<pkg->getItems().size(); i++) {
		IBaseItem *it = pkg->getItems().at(i);

		push_scope(it);
		m_removed = false;
		switch (it->getType()) {
			case IBaseItem::TypeAction:
				// TODO:
				break;

			case IBaseItem::TypeStruct:
				visit_struct(dynamic_cast<IStruct *>(it));
				break;

			case IBaseItem::TypeExtend:
				visit_extend(dynamic_cast<IExtend *>(it));
				break;

			case IBaseItem::TypeImportFunc:
				visit_import_func(dynamic_cast<IImportFunc *>(it));
				break;

			default:
				fprintf(stdout, "Error: Unhandled package item: %d\n", it->getType());
		}
		pop_scope();

		if (m_removed) {
			dynamic_cast<PackageImpl *>(pkg)->remove(it);
			delete it;
		}
	}

	m_removed = false;
}
Beispiel #10
0
void PSIVisitor::visit_comp_pkg_body(const std::vector<IBaseItem *> &items) {
	std::vector<IBaseItem *>::const_iterator it=items.begin();

	for (; it!=items.end(); it++) {
		fprintf(stdout, " -- item %p %d\n", *it, (*it)->getType());
		fflush(stdout);

		push_scope(*it);
		switch ((*it)->getType()) {
			case IBaseItem::TypeAction:
				fprintf(stdout, "---> visit_action\n");
				fflush(stdout);
				visit_action(dynamic_cast<IAction *>(*it));
				fprintf(stdout, "<--- visit_action\n");
				fflush(stdout);
				break;

			case IBaseItem::TypeStruct:
				visit_struct(dynamic_cast<IStruct *>(*it));
				break;
		}
		pop_scope();
	}
}
struct ast* eval_class_native_method(struct method_call_node* m){
  if (m != NULL) {

  	// new
    if (!strcmp(m->method_name, NEW)) {
      //creo objeto
      struct class* class_ptr = find_class(string_value(m->left_ast));	
      struct sym* sym_list = copy_instance_variables_for_class(class_ptr);
      struct ast* new_object = new_object_node(class_ptr, sym_list);

      struct sym* s = find_method_for_class(string_value(m->left_ast), "initialize");

      // initialize está definido
        if (s != NULL) {           
          // llamo a initialize sobre el objeto 
          eval_and_push_args_and_object_info(s->args, m->args, new_object);
          struct ast* eval = eval_ast(s->ast); //eval initialize
          update_instance(new_object); //Antes de hacer pop, salvo en la instancia los cambios en sus variables de instancia
          pop_scope(); // pop del scope pusheado
        };
        return new_object;
      };
  };
};
Beispiel #12
0
static void scan_item(unsigned depth, vpiHandle item, int skip)
{
      struct t_cb_data cb;
      struct vcd_info* info;

      const char* name;
      const char* ident;
      int nexus_id;

      /* list of types to iterate upon */
      int i;
      static int types[] = {
	    /* Value */
	    vpiNet,
	    vpiReg,
	    vpiVariables,
	    /* Scope */
	    vpiFunction,
	    vpiModule,
	    vpiNamedBegin,
	    vpiNamedFork,
	    vpiTask,
	    -1
      };

      switch (vpi_get(vpiType, item)) {

	  case vpiMemoryWord:
	    if (vpi_get(vpiConstantSelect, item) == 0) {
		    /* Turn a non-constant array word select into a
		     * constant word select. */
		  vpiHandle array = vpi_handle(vpiParent, item);
		  PLI_INT32 idx = vpi_get(vpiIndex, item);
		  item = vpi_handle_by_index(array, idx);
	    }
	  case vpiIntegerVar:
	  case vpiBitVar:
	  case vpiByteVar:
	  case vpiShortIntVar:
	  case vpiIntVar:
	  case vpiLongIntVar:
	  case vpiTimeVar:
	  case vpiReg:
	  case vpiNet:

	      /* An array word is implicitly escaped so look for an
	       * escaped identifier that this could conflict with. */
            if (vpi_get(vpiType, item) == vpiMemoryWord &&
                vpi_handle_by_name(vpi_get_str(vpiFullName, item), 0)) {
		  vpi_printf("LXT2 warning: dumping array word %s will "
		             "conflict with an escaped identifier.\n",
		             vpi_get_str(vpiFullName, item));
            }

            if (skip || vpi_get(vpiAutomatic, item)) break;

	    name = vpi_get_str(vpiName, item);
	    nexus_id = vpi_get(_vpiNexusId, item);
	    if (nexus_id) {
		  ident = find_nexus_ident(nexus_id);
	    } else {
		  ident = 0;
	    }

	    if (!ident) {
		  char*tmp = create_full_name(name);
		  ident = strdup_sh(&name_heap, tmp);
		  free(tmp);

		  if (nexus_id) set_nexus_ident(nexus_id, ident);

		  info = new_vcd_info();

		  info->item  = item;
		  info->sym   = lxt2_wr_symbol_add(dump_file, ident,
		                                   0 /* array rows */,
		                                   vpi_get(vpiLeftRange, item),
		                                   vpi_get(vpiRightRange, item),
		                                   LXT2_WR_SYM_F_BITS);
		  info->dmp_next = 0;

		  cb.time      = 0;
		  cb.user_data = (char*)info;
		  cb.value     = NULL;
		  cb.obj       = item;
		  cb.reason    = cbValueChange;
		  cb.cb_rtn    = variable_cb_1;

		  info->cb    = vpi_register_cb(&cb);

	    } else {
		  char *n = create_full_name(name);
		  lxt2_wr_symbol_alias(dump_file, ident, n,
				       vpi_get(vpiSize, item)-1, 0);
		  free(n);
            }

	    break;

	  case vpiRealVar:

            if (skip || vpi_get(vpiAutomatic, item)) break;

	    name = vpi_get_str(vpiName, item);
	    { char*tmp = create_full_name(name);
	      ident = strdup_sh(&name_heap, tmp);
	      free(tmp);
	    }
	    info = new_vcd_info();

	    info->item = item;
	    info->sym  = lxt2_wr_symbol_add(dump_file, ident,
	                                    0 /* array rows */,
	                                    vpi_get(vpiSize, item)-1,
	                                    0, LXT2_WR_SYM_F_DOUBLE);
	    info->dmp_next = 0;

	    cb.time      = 0;
	    cb.user_data = (char*)info;
	    cb.value     = NULL;
	    cb.obj       = item;
	    cb.reason    = cbValueChange;
	    cb.cb_rtn    = variable_cb_1;

	    info->cb    = vpi_register_cb(&cb);

	    break;

	  case vpiModule:
	  case vpiNamedBegin:
	  case vpiTask:
	  case vpiFunction:
	  case vpiNamedFork:

	    if (depth > 0) {
		  int nskip;
		  vpiHandle argv;

		  const char* fullname =
			vpi_get_str(vpiFullName, item);

#if 0
		  vpi_printf("LXT2 info: scanning scope %s, %u levels\n",
		             fullname, depth);
#endif
		  nskip = vcd_scope_names_test(fullname);

		  if (!nskip)
			vcd_scope_names_add(fullname);
		  else
		    vpi_printf("LXT2 warning: ignoring signals in "
		               "previously scanned scope %s\n", fullname);

		  name = vpi_get_str(vpiName, item);

                  push_scope(name);

		  for (i=0; types[i]>0; i++) {
			vpiHandle hand;
			argv = vpi_iterate(types[i], item);
			while (argv && (hand = vpi_scan(argv))) {
			      scan_item(depth-1, hand, nskip);
			}
		  }

                  pop_scope();
	    }
	    break;

	  default:
	    vpi_printf("LXT2 warning: $dumpvars: Unsupported parameter "
	               "type (%s)\n", vpi_get_str(vpiType, item));
      }

}
Beispiel #13
0
void block(char *name, int level) {
	LIST *S = (LIST*)malloc(sizeof(LIST));
    SYMBOL *tmp = NULL;
	/* initial block call */
	if(is_program_block == 1) {
		is_program_block = 0;

		if(token == TK_LBRAC) {
			debug(level,"BLOCK");
			push_scope(name);
			new_function(name, PROG);
			debug_lex(level+1);
			declerations(level+1);
			subprograms(level+1);
			
         	tmp = lookup(name);
         	tmp->func.genquad = qlabel;
			main_start_quad = qlabel;         
			
			genquad("begin_block", program_name, "_", "_");
			sequence(S, level+1);

			if(token == TK_RBRAC) {
				
				
				pop_scope();
				debug_lex();
			} else {
				/* syntax error lpar expected */
				syntax_error("a '}' expected");
			}
		} else {
			/* syntax error rpar expected */
			syntax_error("'{' expected");
		}
		backpatch(S->next, int2string(nextquad()));
		
		genquad("halt", "_", "_", "_");
		genquad("end_block", program_name, "_", "_");
		
		
	} else {

		if(token == TK_LBRAC) {
			debug(level,"BLOCK");
			
			debug_lex(level+1);

			declerations(level+1);
			subprograms(level+1);
            
            tmp = lookup(name);
            tmp->func.genquad = qlabel;

			genquad("begin_block", name, "_", "_");

            fprintf(stderr, "quad quad %s %d\n", tmp->name, tmp->func.genquad);
			
            sequence(S, level+1);
			
			if(token == TK_RBRAC) {
				
				if (!strcmp(assembly, "x86")) {
					generate_final_x86( program_name);
				} else {
					generate_final( program_name);
				}
				
				pop_scope();
				debug_lex();
			} else {
				/* syntax error lpar expected */
				syntax_error("a '}' expected");
			}
			
		} else {
			/* syntax error rpar expected */
			syntax_error("'{' expected");
		}
		backpatch(S->next, int2string(nextquad()));
		genquad("end_block", name,"_", "_");
	}
}
Beispiel #14
0
 ~Scope_guard() { pop_scope(); }
Beispiel #15
0
environment end_scoped_cmd(parser & p) {
    if (in_section(p.env()))
        p.pop_local_scope();
    return pop_scope(p.env());
}
Beispiel #16
0
extern "C" void set_xform_def(XformVar* id, POETCode* code)
{ assert(id != 0); 
  try { curfile->set_xformDef(id,code);  pop_scope(id); }
  catch (Error err) { std::cerr << "\nAt line " << yylineno << " of file " << curfile->get_filename() << "\n"; exit(1); }
}
Beispiel #17
0
static thing_th *delete_enviro_get_nxt(thing_th *enviro, 
                                       thing_th *nxt) {
    pop_scope(Car(enviro));
    del_thing(enviro);
    return nxt;
}
Beispiel #18
0
/* Cover both external declarations, functions, and local declarations (with
 * optional initialization code) inside functions.
 */
struct block *declaration(struct block *parent)
{
    struct typetree *base;
    enum symtype symtype;
    enum linkage linkage;
    int stc = '$';

    base = declaration_specifiers(&stc);
    switch (stc) {
    case EXTERN:
        symtype = SYM_DECLARATION;
        linkage = LINK_EXTERN;
        break;
    case STATIC:
        symtype = SYM_TENTATIVE;
        linkage = LINK_INTERN;
        break;
    case TYPEDEF:
        symtype = SYM_TYPEDEF;
        linkage = LINK_NONE;
        break;
    default:
        if (!ns_ident.current_depth) {
            symtype = SYM_TENTATIVE;
            linkage = LINK_EXTERN;
        } else {
            symtype = SYM_DEFINITION;
            linkage = LINK_NONE;
        }
        break;
    }

    while (1) {
        struct definition *def;
        const char *name = NULL;
        const struct typetree *type;
        struct symbol *sym;

        type = declarator(base, &name);
        if (!name) {
            consume(';');
            return parent;
        }

        sym = sym_add(&ns_ident, name, type, symtype, linkage);
        if (ns_ident.current_depth) {
            assert(ns_ident.current_depth > 1);
            def = current_func();
            def->locals = sym_list_add(def->locals, sym);
        }

        switch (peek().token) {
        case ';':
            consume(';');
            return parent;
        case '=':
            if (sym->symtype == SYM_DECLARATION) {
                error("Extern symbol '%s' cannot be initialized.", sym->name);
                exit(1);
            }
            if (!sym->depth && sym->symtype == SYM_DEFINITION) {
                error("Symbol '%s' was already defined.", sym->name);
                exit(1);
            }
            consume('=');
            sym->symtype = SYM_DEFINITION;
            if (sym->linkage == LINK_NONE) {
                assert(parent);
                parent = initializer(parent, var_direct(sym));
            } else {
                assert(sym->depth || !parent);
                def = push_back_definition(sym);
                initializer(def->body, var_direct(sym));
            }
            assert(size_of(&sym->type) > 0);
            if (peek().token != ',') {
                consume(';');
                return parent;
            }
            break;
        case '{': {
            int i;
            if (!is_function(&sym->type) || sym->depth) {
                error("Invalid function definition.");
                exit(1);
            }
            assert(!parent);
            assert(sym->linkage != LINK_NONE);
            sym->symtype = SYM_DEFINITION;
            def = push_back_definition(sym);
            push_scope(&ns_ident);
            define_builtin__func__(sym->name);
            for (i = 0; i < nmembers(&sym->type); ++i) {
                name = get_member(&sym->type, i)->name;
                type = get_member(&sym->type, i)->type;
                symtype = SYM_DEFINITION;
                linkage = LINK_NONE;
                if (!name) {
                    error("Missing parameter name at position %d.", i + 1);
                    exit(1);
                }
                def->params = sym_list_add(def->params,
                    sym_add(&ns_ident, name, type, symtype, linkage));
            }
            parent = block(def->body);
            pop_scope(&ns_ident);
            return parent;
        }
        default:
            break;
        }
        consume(',');
    }
}
Beispiel #19
0
static void member_declaration_list(struct typetree *type)
{
    struct namespace ns = {0};
    struct typetree *decl_base, *decl_type;
    const char *name;

    push_scope(&ns);

    do {
        decl_base = declaration_specifiers(NULL);

        do {
            name = NULL;
            decl_type = declarator(decl_base, &name);

            if (!name) {
                error("Missing name in member declarator.");
                exit(1);
            } else if (!size_of(decl_type)) {
                error("Field '%s' has incomplete type '%t'.", name, decl_type);
                exit(1);
            } else {
                sym_add(&ns, name, decl_type, SYM_DECLARATION, LINK_NONE);
                type_add_member(type, name, decl_type);
            }

            if (peek().token == ',') {
                consume(',');
                continue;
            }
        } while (peek().token != ';');

        consume(';');
    } while (peek().token != '}');

    pop_scope(&ns);
}

static struct typetree *struct_or_union_declaration(void)
{
    struct symbol *sym = NULL;
    struct typetree *type = NULL;
    enum type kind =
        (next().token == STRUCT) ? T_STRUCT : T_UNION;

    if (peek().token == IDENTIFIER) {
        const char *name = consume(IDENTIFIER).strval;
        sym = sym_lookup(&ns_tag, name);
        if (!sym) {
            type = type_init(kind);
            sym = sym_add(&ns_tag, name, type, SYM_TYPEDEF, LINK_NONE);
        } else if (is_integer(&sym->type)) {
            error("Tag '%s' was previously declared as enum.", sym->name);
            exit(1);
        } else if (sym->type.type != kind) {
            error("Tag '%s' was previously declared as %s.",
                sym->name, (sym->type.type == T_STRUCT) ? "struct" : "union");
            exit(1);
        }

        /* Retrieve type from existing symbol, possibly providing a complete
         * definition that will be available for later declarations. Overwrites
         * existing type information from symbol table. */
        type = &sym->type;
        if (peek().token == '{' && type->size) {
            error("Redefiniton of '%s'.", sym->name);
            exit(1);
        }
    }

    if (peek().token == '{') {
        if (!type) {
            /* Anonymous structure; allocate a new standalone type,
             * not part of any symbol. */
            type = type_init(kind);
        }

        consume('{');
        member_declaration_list(type);
        assert(type->size);
        consume('}');
    }

    /* Return to the caller a copy of the root node, which can be overwritten
     * with new type qualifiers without altering the tag registration. */
    return (sym) ? type_tagged_copy(&sym->type, sym->name) : type;
}

static void enumerator_list(void)
{
    struct var val;
    struct symbol *sym;
    int enum_value = 0;

    consume('{');
    do {
        const char *name = consume(IDENTIFIER).strval;

        if (peek().token == '=') {
            consume('=');
            val = constant_expression();
            if (!is_integer(val.type)) {
                error("Implicit conversion from non-integer type in enum.");
            }
            enum_value = val.imm.i;
        }

        sym = sym_add(
            &ns_ident,
            name,
            &basic_type__int,
            SYM_ENUM_VALUE,
            LINK_NONE);
        sym->enum_value = enum_value++;

        if (peek().token != ',')
            break;
        consume(',');
    } while (peek().token != '}');
    consume('}');
}

static struct typetree *enum_declaration(void)
{
    struct typetree *type = type_init(T_SIGNED, 4);

    consume(ENUM);
    if (peek().token == IDENTIFIER) {
        struct symbol *tag = NULL;
        const char *name = consume(IDENTIFIER).strval;

        tag = sym_lookup(&ns_tag, name);
        if (!tag || tag->depth < ns_tag.current_depth) {
            tag = sym_add(&ns_tag, name, type, SYM_TYPEDEF, LINK_NONE);
        } else if (!is_integer(&tag->type)) {
            error("Tag '%s' was previously defined as aggregate type.",
                tag->name);
            exit(1);
        }

        /* Use enum_value as a sentinel to represent definition, checked on 
         * lookup to detect duplicate definitions. */
        if (peek().token == '{') {
            if (tag->enum_value) {
                error("Redefiniton of enum '%s'.", tag->name);
            }
            enumerator_list();
            tag->enum_value = 1;
        }
    } else {
        enumerator_list();
    }

    /* Result is always integer. Do not care about the actual enum definition,
     * all enums are ints and no type checking is done. */
    return type;
}

static struct typetree get_basic_type_from_specifier(unsigned short spec)
{
    switch (spec) {
    case 0x0001: /* void */
        return basic_type__void;
    case 0x0002: /* char */
    case 0x0012: /* signed char */
        return basic_type__char;
    case 0x0022: /* unsigned char */
        return basic_type__unsigned_char;
    case 0x0004: /* short */
    case 0x0014: /* signed short */
    case 0x000C: /* short int */
    case 0x001C: /* signed short int */
        return basic_type__short;
    case 0x0024: /* unsigned short */
    case 0x002C: /* unsigned short int */
        return basic_type__unsigned_short;
    case 0x0008: /* int */
    case 0x0010: /* signed */
    case 0x0018: /* signed int */
        return basic_type__int;
    case 0x0020: /* unsigned */
    case 0x0028: /* unsigned int */
        return basic_type__unsigned_int;
    case 0x0040: /* long */
    case 0x0050: /* signed long */
    case 0x0048: /* long int */
    case 0x0058: /* signed long int */
    case 0x00C0: /* long long */
    case 0x00D0: /* signed long long */
    case 0x00D8: /* signed long long int */
        return basic_type__long;
    case 0x0060: /* unsigned long */
    case 0x0068: /* unsigned long int */
    case 0x00E0: /* unsigned long long */
    case 0x00E8: /* unsigned long long int */
        return basic_type__unsigned_long;
    case 0x0100: /* float */
        return basic_type__float;
    case 0x0200: /* double */
    case 0x0240: /* long double */
        return basic_type__double;
    default:
        error("Invalid type specification.");
        exit(1); 
    }
}

/* Parse type, qualifiers and storage class. Do not assume int by default, but
 * require at least one type specifier. Storage class is returned as token
 * value, unless the provided pointer is NULL, in which case the input is parsed
 * as specifier-qualifier-list.
 */
struct typetree *declaration_specifiers(int *stc)
{
    struct typetree *type = NULL;
    struct token tok;
    int done = 0;

    /* Use a compact bit representation to hold state about declaration 
     * specifiers. Initialize storage class to sentinel value. */
    unsigned short spec = 0x0000;
    enum qualifier qual = Q_NONE;
    if (stc)       *stc =    '$';

    #define set_specifier(d) \
        if (spec & d) error("Duplicate type specifier '%s'.", tok.strval); \
        next(); spec |= d;

    #define set_qualifier(d) \
        if (qual & d) error("Duplicate type qualifier '%s'.", tok.strval); \
        next(); qual |= d;

    #define set_storage_class(t) \
        if (!stc) error("Unexpected storage class in qualifier list."); \
        else if (*stc != '$') error("Multiple storage class specifiers."); \
        next(); *stc = t;

    do {
        switch ((tok = peek()).token) {
        case VOID:      set_specifier(0x001); break;
        case CHAR:      set_specifier(0x002); break;
        case SHORT:     set_specifier(0x004); break;
        case INT:       set_specifier(0x008); break;
        case SIGNED:    set_specifier(0x010); break;
        case UNSIGNED:  set_specifier(0x020); break;
        case LONG:
            if (spec & 0x040) {
                set_specifier(0x080);
            } else {
                set_specifier(0x040);   
            }
            break;
        case FLOAT:     set_specifier(0x100); break;
        case DOUBLE:    set_specifier(0x200); break;
        case CONST:     set_qualifier(Q_CONST); break;
        case VOLATILE:  set_qualifier(Q_VOLATILE); break;
        case IDENTIFIER: {
            struct symbol *tag = sym_lookup(&ns_ident, tok.strval);
            if (tag && tag->symtype == SYM_TYPEDEF && !type) {
                consume(IDENTIFIER);
                type = type_init(T_STRUCT);
                *type = tag->type;
            } else {
                done = 1;
            }
            break;
        }
        case UNION:
        case STRUCT:
            if (!type) {
                type = struct_or_union_declaration();
            } else {
                done = 1;
            }
            break;
        case ENUM:
            if (!type) {
                type = enum_declaration();
            } else {
                done = 1;
            }
            break;
        case AUTO:
        case REGISTER:
        case STATIC:
        case EXTERN:
        case TYPEDEF:
            set_storage_class(tok.token);
            break;
        default:
            done = 1;
            break;
        }

        if (type && spec) {
            error("Invalid combination of declaration specifiers.");
            exit(1);
        }
    } while (!done);

    #undef set_specifier
    #undef set_qualifier
    #undef set_storage_class

    if (type) {
        if (qual & type->qualifier) {
            error("Duplicate type qualifier:%s%s.",
                (qual & Q_CONST) ? " const" : "",
                (qual & Q_VOLATILE) ? " volatile" : "");
        }
    } else if (spec) {
        type = type_init(T_STRUCT);
        *type = get_basic_type_from_specifier(spec);
    } else {
        error("Missing type specifier.");
        exit(1);
    }

    type->qualifier |= qual;
    return type;
}

/* Set var = 0, using simple assignment on members for composite types. This
 * rule does not consume any input, but generates a series of assignments on the
 * given variable. Point is to be able to zero initialize using normal simple
 * assignment rules, although IR can become verbose for large structures.
 */
static void zero_initialize(struct block *block, struct var target)
{
    int i;
    struct var var;
    assert(target.kind == DIRECT);

    switch (target.type->type) {
    case T_STRUCT:
    case T_UNION:
        target.type = unwrapped(target.type);
        var = target;
        for (i = 0; i < nmembers(var.type); ++i) {
            target.type = get_member(var.type, i)->type;
            target.offset = var.offset + get_member(var.type, i)->offset;
            zero_initialize(block, target);
        }
        break;
    case T_ARRAY:
        assert(target.type->size);
        var = target;
        target.type = target.type->next;
        assert(is_struct(target.type) || !target.type->next);
        for (i = 0; i < var.type->size / var.type->next->size; ++i) {
            target.offset = var.offset + i * var.type->next->size;
            zero_initialize(block, target);
        }
        break;
    case T_POINTER:
        var = var_zero(8);
        var.type = type_init(T_POINTER, &basic_type__void);
        eval_assign(block, target, var);
        break;
    case T_UNSIGNED:
    case T_SIGNED:
        var = var_zero(target.type->size);
        eval_assign(block, target, var);
        break;
    default:
        error("Invalid type to zero-initialize, was '%t'.", target.type);
        exit(1);
    }
}