1 // Semantic actions for types and namespaces
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // This software is provided 'as-is', without any express or implied warranty.
6 // In no event will the authors or contributors be held liable for any damages
7 // arising from the use of this software.
9 // Permission is hereby granted to everyone, free of charge, to use, copy,
10 // modify, prepare derivative works of, publish, distribute, perform,
11 // sublicense, and/or sell copies of the Software, provided that the above
12 // copyright notice and disclaimer of warranty be included in all copies or
13 // substantial portions of this software.
22 bool Datum::verify_const()
24 assert(def.flags.field.Const);
26 // TOK_INVALID should have caused an abort in an earlier pass, and
27 // TOK_DCON should have been replaced by the final constant by now.
29 assert(con_type == TOK_ICON || con_type == TOK_UCON ||
30 con_type == TOK_FCON || con_type == TOK_BOOL);
32 if (cbt->flags.field.Float) {
33 if (con_type == TOK_UCON)
34 def.fcon = static_cast<double>(def.ucon);
35 else if (con_type == TOK_ICON)
36 def.fcon = static_cast<double>(def.icon);
37 else if (con_type == TOK_BOOL) {
38 yyerrorfl(name->file, name->line,
39 "%s is of floating-point type, but is initialized with "
40 "a boolean constant.", name->c_str());
47 if (cbt->bits == 32) {
48 if (def.fcon > FLT_MAX || def.fcon < FLT_MIN) {
49 yyerrorfl(name->file, name->line,
50 "%s is out of range for a single-precision FP datum.",
61 if (con_type == TOK_FCON) {
62 yyerrorfl(name->file, name->line,
63 "%s is of %s type, but is initialized with "
64 "a floating-point constant.",
65 cbt->flags.field.Bool ? "boolean" : "integral",
71 if (cbt->flags.field.Bool) {
72 if (con_type != TOK_BOOL) {
73 yyerrorfl(name->file, name->line,
74 "%s is of boolean type, but is initialized with "
75 "a non-boolean constant.", name->c_str());
80 assert(def.ucon == 0 || def.ucon == 1);
86 if (con_type == TOK_BOOL) {
87 yyerrorfl(name->file, name->line,
88 "%s is of integral type, but is initialized with "
89 "a boolean constant.", name->c_str());
94 if (cbt->flags.field.Unsigned) {
95 if (con_type == TOK_ICON && def.icon < 0) {
96 yyerrorfl(name->file, name->line,
97 "Initializer for \"%s\" is out of range.",
102 if (cbt->bits < 64) {
103 uint64_t max = (1ULL << cbt->bits) - 1;
105 if (def.ucon > max) {
106 yyerrorfl(name->file, name->line,
107 "Initializer for \"%s\" is out of range.",
113 if (con_type == TOK_UCON && def.icon < 0) {
114 yyerrorfl(name->file, name->line,
115 "Initializer for \"%s\" is out of range.",
120 if (cbt->bits < 64) {
121 // Yes, the constant should be unsigned before conversion,
122 // as the temporary value could overflow a signed datum
123 // before the one is subtracted if bits == 63. It won't
124 // matter on most machines, but you never know...
126 int64_t max = (1ULL << (cbt->bits - 1)) - 1;
128 if (def.icon > max || def.icon < -max + 1) {
129 yyerrorfl(name->file, name->line,
130 "Initializer for \"%s\" is out of range.",
141 void Datum::init_const_early(Con *con)
144 if (con->type == TOK_DCON) {
145 assert(current_pass == 1);
146 const_val_name = con->con.dcon;
149 def.flags.field.Const = 1;
150 con_type = con->type;
151 def.ucon = con->con.ucon;
155 void Datum::init(StrList *type, Array *ARRAY, Con *con)
166 init_const_early(con);
169 void Datum::init(CompiledBasicType &CBT, Array *ARRAY, Con *con)
174 cbt = &def.basictype;
180 init_const_early(con);
183 void Datum::process_type()
185 assert(current_pass >= 4);
190 assert(!type_fq_name);
193 Symbol *sym = type_sym->get_concrete_sym(false);
194 type = dynamic_cast<Type *>(sym);
197 const String *str = type_name->back();
198 yyerrorfl(str->file, str->line, "\"%s\" is not a type.",
199 sym->get_fq_name()->flatten()->c_str());
204 BasicType *bt = dynamic_cast<BasicType *>(type->get_concrete_sym());
207 if (!bt->def.flags.field.TypeDef)
208 use_anon_type(bt->def);
211 } else if (const_val) {
212 const String *str = type_name->back();
213 yyerrorfl(str->file, str->line,
214 "\"%s\" is not a basic type (and thus \"%s\" cannot "
216 type->get_fq_name()->flatten()->c_str(),
222 type_fq_name = type->get_fq_name()->flatten();
223 def.type.length = type_fq_name->length();
227 Datum *Datum::resolve_constant_chain()
229 if (chain_traversed == traversal) {
230 yyerrorfl(name->file, name->line,
231 "Initialization of \"%s\" forms an infinite loop:",
232 get_fq_name()->flatten()->c_str());
236 chain_traversed = traversal;
244 const_val = dynamic_cast<Datum *>(const_val_sym->get_concrete_sym());
247 const String *str = const_val_name->back();
248 yyerrorfl(str->file, str->line, "\"%s\" is not a datum.",
249 const_val_sym->get_fq_name()->flatten()->c_str());
253 if (!const_val->def.flags.field.Const) {
254 const String *str = const_val_name->back();
255 yyerrorfl(str->file, str->line, "\"%s\" is not a constant.",
256 const_val->get_fq_name()->flatten()->c_str());
260 if (!const_val->const_init) {
261 Datum *d = const_val->resolve_constant_chain();
263 yyerrorfl(name->file, name->line, "...initializes \"%s\"",
264 get_fq_name()->flatten()->c_str());
273 assert(const_val->const_init);
275 con_type = const_val->con_type;
276 def.ucon = const_val->def.ucon;
286 // FIXME: Check for inline struct loops.
287 void Datum::final_analysis()
289 Struct *str = dynamic_cast<Struct *>(*type);
290 if (str && str->is_inline())
294 array->final_analysis();
295 def.basictype.array = array->ca;
297 def.basictype.array.bounds[0] = 0;
298 def.basictype.array.bounds[1] = 0;
301 BitField *bfparent = dynamic_cast<BitField *>(get_ns());
309 defsize = type->get_default_bf_size();
312 yyerrorfl(name->file, name->line,
313 "\"%s\" may not be the named type of bitfield entry "
314 "\"%s\", as it is not a bitfield or enumeration.",
315 type->get_fq_name()->flatten()->c_str(),
316 get_fq_name()->flatten()->c_str());
317 } else if (def.icon == -1) {
319 } else if (def.ucon < (unsigned int)defsize) {
320 yyerrorfl(name->file, name->line,
321 "Explicit size %llu on \"%s\" is too small for "
322 "type \"%s\", which has a minimum size of %u",
323 (unsigned long long)def.ucon,
324 get_fq_name()->flatten()->c_str(),
325 type->get_fq_name()->flatten()->c_str(), defsize);
330 void Struct::add(Symbol *sym, bool from_import)
332 Datum *datum = dynamic_cast<Datum *>(sym);
334 if (!datum && !dynamic_cast<Alias *>(sym) &&
335 !dynamic_cast<Type *>(sym) &&
336 !dynamic_cast<Method *>(sym))
337 throw InvalidArgument();
339 NameSpace::add(sym, from_import);
341 if (!from_import && datum && !datum->def.flags.field.Const)
345 void Struct::add_elem(Datum *d)
347 entries.push_back(d);
351 Param *Param::declare(const String *name, NameSpace *parent,
352 StrList *TYPE, CompiledParam::Flags flags,
356 assert(dynamic_cast<Method *>(parent));
358 Param *p = new Param(name);
359 p->init(TYPE, flags, array);
365 Method *Method::declare(const String *name, NameSpace *parent)
368 assert(dynamic_cast<Interface *>(parent));
370 Method *m = new Method(name);
376 void Interface::add(Symbol *sym, bool from_import)
378 Datum *datum = dynamic_cast<Datum *>(sym);
379 Method *method = dynamic_cast<Method *>(sym);
381 if (!datum && !method &&
382 !dynamic_cast<Alias *>(sym) &&
383 !dynamic_cast<Type *>(sym))
384 throw InvalidArgument();
386 if (datum && !datum->def.flags.field.Const)
387 throw InvalidArgument();
389 NameSpace::add(sym, from_import);
391 if (!from_import && method)
395 // FIXME: check for duplicate and looping inheritance
396 void Interface::add_elem(Method *method)
398 methods.push_back(method);
402 void Enum::add(Symbol *sym, bool from_import)
404 Datum *datum = dynamic_cast<Datum *>(sym);
406 // It also must be const unsigned, but the const won't
407 // have been initialized yet.
410 throw InvalidArgument();
412 NameSpace::add(sym, from_import);
418 void Enum::add_elem(Datum *datum)
420 entries.push_back(datum);
424 void BitField::add(Symbol *sym, bool from_import)
426 Datum *datum = dynamic_cast<Datum *>(sym);
428 if (!datum && !dynamic_cast<Enum *>(sym) &&
429 !dynamic_cast<BitField *>(sym))
430 throw InvalidArgument();
432 NameSpace::add(sym, from_import);
434 if (!from_import && datum)
438 void BitField::add_elem(Datum *datum)
440 entries.push_back(datum);
444 void Method::add(Symbol *sym, bool from_import)
446 Param *param = dynamic_cast<Param *>(sym);
449 throw InvalidArgument();
451 NameSpace::add(sym, from_import);
456 void Method::add_elem(Param *param)
458 entries.push_back(param);
462 // Use this rather than lookup_sym if you want to check for built-in types.
463 // If only constructed types are valid, use lookup_sym. If basic_types_only
464 // is set, then NULL will be returned if sl does not describe a built-in
465 // basic type (such as int, flong, octet, etc). This option is used so that
466 // the first-pass code in idlparse.y can decide whether to create a BasicType
467 // or an Alias/TypeDef.
469 Type *lookup_type(StrList *sl, NameSpace *ctx, bool basic_types_only)
472 int token = sl->front()->token;
474 // These tokens aren't valid types, but the names can be
475 // used as identifiers.
483 // Treat it as a user-defined type if it's either not a reserved word,
484 // or if there are multiple components.
486 if (token == TOK_IDENT || sl->front() != sl->back()) {
487 if (basic_types_only)
490 Symbol *sym = lookup_sym(toplevel, sl, ctx);
491 type = dynamic_cast<Type *>(sym->get_concrete_sym(false));
494 const String *str = sl->back();
495 yyerrorfl(str->file, str->line, "\"%s\" is not a type.",
496 sym->get_fq_name()->flatten()->c_str());
501 CompiledBasicType cbt;
502 memset(&cbt, 0, sizeof(cbt));
507 cbt.flags.field.Bool = 1;
513 cbt.flags.field.Unsigned = 1;
530 cbt.flags.field.Unsigned = 1;
535 cbt.flags.field.Unsigned = 1;
540 cbt.flags.field.Unsigned = 1;
545 cbt.flags.field.Float = 1;
550 cbt.flags.field.Float = 1;
554 fprintf(stderr, "token %d\n", token);
558 type = BasicType::declare(sl->front(), NULL, cbt);
564 void declare_data(NameSpace *ns, StrList *ids, StrList *type,
565 Array *array, StrList *attr)
567 bool is_inline = false;
568 bool is_immutable = false;
571 for (StrList::iterator i = attr->begin(); i != attr->end(); ++i) {
572 const String *this_attr = *i;
574 switch (this_attr->token) {
584 yyerrorfl(this_attr->file, this_attr->line,
585 "Invalid attribute \"%s\"", (*i)->c_str());
590 for (StrList::iterator i = ids->begin(); i != ids->end(); ++i) {
592 Datum *d = Datum::declare(*i, ns, type, array);
602 // An error has already been displayed, but try to
603 // continue and find more errors.
608 void declare_aliases(NameSpace *ns, StrList *ids, StrList *type,
613 for (i = ids->begin(); i != ids->end(); ++i) {
616 TypeDef::declare(*i, ns, type);
618 Alias::declare(*i, ns, type);
622 // An error has already been displayed, but try to
623 // continue and find more errors.
628 void declare_basictypes(NameSpace *ns, StrList *ids,
629 BasicType *type, bool is_typedef)
631 assert(!type->def.flags.field.TypeDef);
634 for (i = ids->begin(); i != ids->end(); ++i) {
637 BasicType::declare(*i, ns, type->def);
639 bt->def.flags.field.TypeDef = is_typedef;
643 // An error has already been displayed, but try to
644 // continue and find more errors.
649 Array::Array(NameSpace *LOOKUP_CTX)
651 lookup_ctx = LOOKUP_CTX;
653 for (int i = 0; i < 2; i++) {
654 cons[i].con.ucon = 0;
655 cons[i].type = TOK_UCON;
659 void Array::set_unbounded()
661 for (int i = 0; i < 2; i++)
662 cons[i].type = TOK_NONE;
665 void Array::final_analysis()
667 for (int i = 0; i < 2; i++) {
668 if (cons[i].type == TOK_NONE) {
677 if (cons[i].type == TOK_DCON) {
678 Symbol *sym = lookup_sym(toplevel, dcons[i], lookup_ctx);
679 datums[i] = dynamic_cast<Datum *>(sym);
681 const String *str = dcons[i]->back();
682 yyerrorfl(str->file, str->line, "\"%s\" is not a Datum.",
683 sym->get_fq_name()->flatten()->c_str());
687 ca.bounds[i] = datums[i]->get_ucon(dcons[i]->back());
688 cons[i].type = datums[i]->con_type;
690 ca.bounds[i] = cons[i].con.ucon;
693 if (cons[i].type == TOK_FCON) {
694 yyerrorfl(strs[i]->file, strs[i]->line,
695 "\"%s\" is not an integral Datum.",
700 if (ca.bounds[i] < 0) {
701 yyerrorfl(strs[i]->file, strs[i]->line,
702 "\"%s\" %s.", strs[i]->c_str(),
703 cons[i].type == TOK_UCON ?
704 "does not fit in a signed 64-bit integer" :
710 if (ca.bounds[1] >= 0 && ca.bounds[0] > ca.bounds[1]) {
711 yyerrorfl(strs[0]->file, strs[0]->line,
712 "\"%s\" is larger than \"%s\".",
713 strs[0]->c_str(), strs[1]->c_str());
718 void Array::set_bound(Con &con, int bound)
720 assert(current_pass == 1);
722 if (con.type == TOK_FCON) {
723 yyerrorf("Array limits must be integers.");
727 if (con.type == TOK_ICON && con.con.icon <= 0) {
728 yyerrorf("Array limits must be positive");
732 if (con.type == TOK_UCON && con.con.icon <= 0) {
733 yyerrorf("Array limits must fit in a signed 64-bit integer");
739 if (con.type == TOK_DCON) {
740 assert(con.con.dcon);
741 dcons[bound] = con.con.dcon;
742 strs[bound] = con.con.dcon->flatten();
744 std::ostringstream ss(std::ostringstream::out);
769 strs[bound] = new String(ss.str().c_str(), cur_input_file,
775 void UserNameSpace::output_lang(LangCallback *lcb, int arg1, void *arg2)
777 lcb->output(this, arg1, arg2);
780 void BasicType::output_lang(LangCallback *lcb, int arg1, void *arg2)
782 lcb->output(this, arg1, arg2);
785 void Interface::output_lang(LangCallback *lcb, int arg1, void *arg2)
787 lcb->output(this, arg1, arg2);
790 void Struct::output_lang(LangCallback *lcb, int arg1, void *arg2)
792 lcb->output(this, arg1, arg2);
795 void BitField::output_lang(LangCallback *lcb, int arg1, void *arg2)
797 lcb->output(this, arg1, arg2);
800 void Enum::output_lang(LangCallback *lcb, int arg1, void *arg2)
802 lcb->output(this, arg1, arg2);
805 void Alias::output_lang(LangCallback *lcb, int arg1, void *arg2)
807 lcb->output(this, arg1, arg2);
810 void TypeDef::output_lang(LangCallback *lcb, int arg1, void *arg2)
812 lcb->output(this, arg1, arg2);
815 void Datum::output_lang(LangCallback *lcb, int arg1, void *arg2)
817 if (def.flags.field.Const)
818 lcb->output(this, arg1, arg2);
821 void Method::output_lang(LangCallback *lcb, int arg1, void *arg2)
825 void Param::output_lang(LangCallback *lcb, int arg1, void *arg2)
829 int Interface::all_supers_traversal;