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 def.ucon, get_fq_name()->flatten()->c_str(),
324 type->get_fq_name()->flatten()->c_str(), defsize);
329 void Struct::add(Symbol *sym, bool from_import)
331 Datum *datum = dynamic_cast<Datum *>(sym);
333 if (!datum && !dynamic_cast<Alias *>(sym) &&
334 !dynamic_cast<Type *>(sym) &&
335 !dynamic_cast<Method *>(sym))
336 throw InvalidArgument();
338 NameSpace::add(sym, from_import);
340 if (!from_import && datum && !datum->def.flags.field.Const)
344 void Struct::add_elem(Datum *d)
346 entries.push_back(d);
350 Param *Param::declare(const String *name, NameSpace *parent,
351 StrList *TYPE, CompiledParam::Flags flags,
355 assert(dynamic_cast<Method *>(parent));
357 Param *p = new Param(name);
358 p->init(TYPE, flags, array);
364 Method *Method::declare(const String *name, NameSpace *parent)
367 assert(dynamic_cast<Interface *>(parent));
369 Method *m = new Method(name);
375 void Interface::add(Symbol *sym, bool from_import)
377 Datum *datum = dynamic_cast<Datum *>(sym);
378 Method *method = dynamic_cast<Method *>(sym);
380 if (!datum && !method &&
381 !dynamic_cast<Alias *>(sym) &&
382 !dynamic_cast<Type *>(sym))
383 throw InvalidArgument();
385 if (datum && !datum->def.flags.field.Const)
386 throw InvalidArgument();
388 NameSpace::add(sym, from_import);
390 if (!from_import && method)
394 // FIXME: check for duplicate and looping inheritance
395 void Interface::add_elem(Method *method)
397 methods.push_back(method);
401 void Enum::add(Symbol *sym, bool from_import)
403 Datum *datum = dynamic_cast<Datum *>(sym);
405 // It also must be const unsigned, but the const won't
406 // have been initialized yet.
409 throw InvalidArgument();
411 NameSpace::add(sym, from_import);
417 void Enum::add_elem(Datum *datum)
419 entries.push_back(datum);
423 void BitField::add(Symbol *sym, bool from_import)
425 Datum *datum = dynamic_cast<Datum *>(sym);
427 if (!datum && !dynamic_cast<Enum *>(sym) &&
428 !dynamic_cast<BitField *>(sym))
429 throw InvalidArgument();
431 NameSpace::add(sym, from_import);
433 if (!from_import && datum)
437 void BitField::add_elem(Datum *datum)
439 entries.push_back(datum);
443 void Method::add(Symbol *sym, bool from_import)
445 Param *param = dynamic_cast<Param *>(sym);
448 throw InvalidArgument();
450 NameSpace::add(sym, from_import);
455 void Method::add_elem(Param *param)
457 entries.push_back(param);
461 // Use this rather than lookup_sym if you want to check for built-in types.
462 // If only constructed types are valid, use lookup_sym. If basic_types_only
463 // is set, then NULL will be returned if sl does not describe a built-in
464 // basic type (such as int, flong, octet, etc). This option is used so that
465 // the first-pass code in idlparse.y can decide whether to create a BasicType
466 // or an Alias/TypeDef.
468 Type *lookup_type(StrList *sl, NameSpace *ctx, bool basic_types_only)
471 int token = sl->front()->token;
473 // These tokens aren't valid types, but the names can be
474 // used as identifiers.
482 // Treat it as a user-defined type if it's either not a reserved word,
483 // or if there are multiple components.
485 if (token == TOK_IDENT || sl->front() != sl->back()) {
486 if (basic_types_only)
489 Symbol *sym = lookup_sym(toplevel, sl, ctx);
490 type = dynamic_cast<Type *>(sym->get_concrete_sym(false));
493 const String *str = sl->back();
494 yyerrorfl(str->file, str->line, "\"%s\" is not a type.",
495 sym->get_fq_name()->flatten()->c_str());
500 CompiledBasicType cbt;
501 memset(&cbt, 0, sizeof(cbt));
506 cbt.flags.field.Bool = 1;
512 cbt.flags.field.Unsigned = 1;
529 cbt.flags.field.Unsigned = 1;
534 cbt.flags.field.Unsigned = 1;
539 cbt.flags.field.Unsigned = 1;
544 cbt.flags.field.Float = 1;
549 cbt.flags.field.Float = 1;
553 fprintf(stderr, "token %d\n", token);
557 type = BasicType::declare(sl->front(), NULL, cbt);
563 void declare_data(NameSpace *ns, StrList *ids, StrList *type,
564 Array *array, StrList *attr)
566 bool is_inline = false;
567 bool is_immutable = false;
570 for (StrList::iterator i = attr->begin(); i != attr->end(); ++i) {
571 const String *this_attr = *i;
573 switch (this_attr->token) {
583 yyerrorfl(this_attr->file, this_attr->line,
584 "Invalid attribute \"%s\"", (*i)->c_str());
589 for (StrList::iterator i = ids->begin(); i != ids->end(); ++i) {
591 Datum *d = Datum::declare(*i, ns, type, array);
601 // An error has already been displayed, but try to
602 // continue and find more errors.
607 void declare_aliases(NameSpace *ns, StrList *ids, StrList *type,
612 for (i = ids->begin(); i != ids->end(); ++i) {
615 TypeDef::declare(*i, ns, type);
617 Alias::declare(*i, ns, type);
621 // An error has already been displayed, but try to
622 // continue and find more errors.
627 void declare_basictypes(NameSpace *ns, StrList *ids,
628 BasicType *type, bool is_typedef)
630 assert(!type->def.flags.field.TypeDef);
633 for (i = ids->begin(); i != ids->end(); ++i) {
636 BasicType::declare(*i, ns, type->def);
638 bt->def.flags.field.TypeDef = is_typedef;
642 // An error has already been displayed, but try to
643 // continue and find more errors.
648 Array::Array(NameSpace *LOOKUP_CTX)
650 lookup_ctx = LOOKUP_CTX;
652 for (int i = 0; i < 2; i++) {
653 cons[i].con.ucon = 0;
654 cons[i].type = TOK_UCON;
658 void Array::set_unbounded()
660 for (int i = 0; i < 2; i++)
661 cons[i].type = TOK_NONE;
664 void Array::final_analysis()
666 for (int i = 0; i < 2; i++) {
667 if (cons[i].type == TOK_NONE) {
676 if (cons[i].type == TOK_DCON) {
677 Symbol *sym = lookup_sym(toplevel, dcons[i], lookup_ctx);
678 datums[i] = dynamic_cast<Datum *>(sym);
680 const String *str = dcons[i]->back();
681 yyerrorfl(str->file, str->line, "\"%s\" is not a Datum.",
682 sym->get_fq_name()->flatten()->c_str());
686 ca.bounds[i] = datums[i]->get_ucon(dcons[i]->back());
687 cons[i].type = datums[i]->con_type;
689 ca.bounds[i] = cons[i].con.ucon;
692 if (cons[i].type == TOK_FCON) {
693 yyerrorfl(strs[i]->file, strs[i]->line,
694 "\"%s\" is not an integral Datum.",
699 if (ca.bounds[i] < 0) {
700 yyerrorfl(strs[i]->file, strs[i]->line,
701 "\"%s\" %s.", strs[i]->c_str(),
702 cons[i].type == TOK_UCON ?
703 "does not fit in a signed 64-bit integer" :
709 if (ca.bounds[1] >= 0 && ca.bounds[0] > ca.bounds[1]) {
710 yyerrorfl(strs[0]->file, strs[0]->line,
711 "\"%s\" is larger than \"%s\".",
712 strs[0]->c_str(), strs[1]->c_str());
717 void Array::set_bound(Con &con, int bound)
719 assert(current_pass == 1);
721 if (con.type == TOK_FCON) {
722 yyerrorf("Array limits must be integers.");
726 if (con.type == TOK_ICON && con.con.icon <= 0) {
727 yyerrorf("Array limits must be positive");
731 if (con.type == TOK_UCON && con.con.icon <= 0) {
732 yyerrorf("Array limits must fit in a signed 64-bit integer");
738 if (con.type == TOK_DCON) {
739 assert(con.con.dcon);
740 dcons[bound] = con.con.dcon;
741 strs[bound] = con.con.dcon->flatten();
743 std::ostringstream ss(std::ostringstream::out);
768 strs[bound] = new String(ss.str().c_str(), cur_input_file,
774 void UserNameSpace::output_lang(LangCallback *lcb, int arg1, void *arg2)
776 lcb->output(this, arg1, arg2);
779 void BasicType::output_lang(LangCallback *lcb, int arg1, void *arg2)
781 lcb->output(this, arg1, arg2);
784 void Interface::output_lang(LangCallback *lcb, int arg1, void *arg2)
786 lcb->output(this, arg1, arg2);
789 void Struct::output_lang(LangCallback *lcb, int arg1, void *arg2)
791 lcb->output(this, arg1, arg2);
794 void BitField::output_lang(LangCallback *lcb, int arg1, void *arg2)
796 lcb->output(this, arg1, arg2);
799 void Enum::output_lang(LangCallback *lcb, int arg1, void *arg2)
801 lcb->output(this, arg1, arg2);
804 void Alias::output_lang(LangCallback *lcb, int arg1, void *arg2)
806 lcb->output(this, arg1, arg2);
809 void TypeDef::output_lang(LangCallback *lcb, int arg1, void *arg2)
811 lcb->output(this, arg1, arg2);
814 void Datum::output_lang(LangCallback *lcb, int arg1, void *arg2)
816 if (def.flags.field.Const)
817 lcb->output(this, arg1, arg2);
820 void Method::output_lang(LangCallback *lcb, int arg1, void *arg2)
824 void Param::output_lang(LangCallback *lcb, int arg1, void *arg2)
828 int Interface::all_supers_traversal;