]> git.buserror.net Git - polintos/scott/priv.git/blob - idlcomp/main.cc
Add copyright to idlcomp files that were previously just "Written by:".
[polintos/scott/priv.git] / idlcomp / main.cc
1 // Entry point for the interface compiler
2 //
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
4 // 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal with
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 // of the Software, and to permit persons to whom the Software is furnished to do
10 // so, subject to the following condition:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
21 // SOFTWARE.
22 //
23 // The idlc program implements two main functions.  One is to turn
24 // .idl files into binary type descriptions.  The other is to turn
25 // those type descriptions into language-specific stubs (though a
26 // compiler/interpreter could also just read the binary types
27 // directly, as the ORB does).
28 //
29 // For the former function, it is necessary to do the work in multiple
30 // passes, as not all information is available the first time through due
31 // to the absence of forward declarations.  The passes are as follows:
32 //
33 //   1: Parse the input text, and determine which symbols exist in
34 //      which namespaces.  At this point, no non-namespace-qualified
35 //      symbol lookups will be done (though namespace-qualified lookups
36 //      are done, such as to check for duplicate symbols).
37 //
38 //      Objects will be created for each entity (Interface, Struct,
39 //      Datum, Alias, etc.), but any reference to another entity will be
40 //      stored as a StrList, not as an object pointer.  This must be the
41 //      case even if a lookup during this pass would have found
42 //      something, as on the second pass it might find a "closer"
43 //      matching symbol added later.
44 //
45 //      The StrList will later be looked up with only the entity
46 //      containing the reference as context, so namespace search rules
47 //      must not depend on anything else.
48 //
49 //      This is the only pass that involves actually reading and
50 //      parsing the input file(s).
51 //
52 //   2: Look up the namespace names of using namespace.* statements.
53 //      These are the only lookups where order of the statements in the
54 //      file matters, and it alters the result of a lookup, so it must be
55 //      completed before chain lookups are done.
56 //
57 //   3: Look up the symbol names recorded in pass 1 for aliases, and
58 //      typedefs, and const datum initializers and types. This is done
59 //      before the rest of the lookups, so there will always be a
60 //      complete chain to follow in subsequent passes.
61 //
62 //      This is done by calling the virtual lookup_chain() method on
63 //      the root namespace, which recursively calls it on all of its
64 //      contents.
65 //
66 //   4: Look up other symbol names recorded in pass 1.  At this point,
67 //      unresolved alias chains may still exist and must be handled,
68 //      though they should be fixed during this phase so that they do not
69 //      appear in phase 4.  Typedefs will remain fully chained, as the
70 //      chain is semantically meaningful and must be preserved in the
71 //      output. 
72 //      
73 //      Const datum initializers are looked up in this pass despite being
74 //      chains, since aliases aren't resolved in pass 2, and it's
75 //      (slightly) easier to do the lookup in pass 3 and resolve the
76 //      chain in pass 4 than to store a Symbol reference in pass 2,
77 //      get the concerete sym in pass 3, and still have to either
78 //      concrete-ize other Datums' initializers or wait until pass 4
79 //      to resolve the chain.
80 //
81 //      This is done by calling the virtual lookup_misc() method on the
82 //      root namespace, which recursively calls it on all of its
83 //      contents.  Upon receiving this call, each entity object should
84 //      call lookup_sym() or lookup_type() on the various StrLists it has
85 //      stored, but should not do anything with the object pointer
86 //      until pass 4 (unless the object was satisfactorily initialized
87 //      in pass 1).
88 //
89 //   5: Perform any remaining semantic analysis, now that all references
90 //      to other entities have been looked up.  
91 //
92 //      This is done by calling the virtual final_analysis() method on
93 //      the root namespace, which recursively calls it on all of its
94 //      contents.
95 //
96 //   6: Generate output.
97 //      This is done by calling the virtual output() method on
98 //      the root namespace, which recursively calls it on all of its
99 //      contents.
100 //
101 // All circular dependencies must be contained within the set of files
102 // passed to the compiler in one invocation.  Supporting circular
103 // dependencies over multiple invocations of the compiler would require
104 // explicitly running only certain passes, then compiling the other
105 // batch, and then finishing the original batch.  It could be done with
106 // some pain (intermediate states would need to be serialized), but I
107 // only want to do it if there's a real need.  Circular dependencies
108 // ought to be isolated fairly locally...
109
110 #include <climits>
111 #include <cstdio>
112 #include <cstdarg>
113 #include <cstring>
114 #include <cstdlib>
115 #include <cerrno>
116
117 #include <idlc.h>
118 #include <lang.h>
119 #include <targets.h>
120 #include <util.h>
121
122 int num_err;
123 unsigned int enum_pos;
124 bool no_output;
125 bool server_stubs;
126 bool makedep;
127 int current_pass;
128 int traversal;
129 Con *yylval_con;
130 String **yylval_string;
131
132 UserNameSpaceRef toplevel, cdl_toplevel;
133 UserNameSpace *output_ns;
134 NameSpaceRef cur_nspace;
135 const char *cmdname, *output_dir, *cur_input_file = "<none>", *output_ns_name;
136
137 list<const char *> inputs;
138 list<NameSpaceRef> nspace_stack;
139 Language *first_lang, *output_lang;
140 Interface *System_Object;
141 Struct *System_VStruct;
142 AutoReleasePool autorelease_pool;
143
144 void print_usage()
145 {
146         fprintf(stderr,
147 "Usage: %s [options] [<input(s)>]\n\n"
148 "Options are:\n"
149 "-d (--debug)           Print parser debugging information.\n"
150 "-h (--help)            Print this help screen.\n"
151 "-i DIR (--include=DIR) Look in DIR for resolving external type definitions.\n"
152 "                       Multiple include directories can be specified, and\n"
153 "                       will be mounted at the --namespace specified when\n"
154 "                       they were created.\n"
155 "-l LANG (--lang=LANG)  Generate stubs for this language.\n"
156 "-M (--makedep)         Output dependency information for make.\n"
157 "-n (--no-output)       Do not produce output; only check for errors.\n"
158 "-o DIR (--output=DIR)  Generate output in DIR.\n"
159 "-r (--server)          Generate server stubs according to the input CDL files.\n"
160 "-s NS (--namespace=NS) Input files constitute the given namespace.\n"
161 "-t TARGET (--target=T) Generate stubs for the specified target architecture.\n"
162 "                       By default, the current architecture is targeted.\n"
163 "--show-languages       List languages for which stub generation is supported.\n"
164 "--show-targets         List supported target architectures.\n"
165 "If a language is specified, language-specific stubs for the output --namespace\n"
166 "will be placed in the specified output directory.  All inputs must be specified\n"
167 "as --includes (including all components of the output namespace and anything\n"
168 "referenced by them).  No non-option inputs may be specified.\n\n"
169 "If a language is not specified, inputs are treated as IDL source\n"
170 "files, and are compiled into the specified output directory, as\n"
171 "the specified output --namespace.\n\n",
172 cmdname);
173 }
174
175 static void set_lang(const char *lang)
176 {
177         if (output_lang) {
178                 fprintf(stderr, "Only one language may be specified.\n");
179                 throw UserError();
180         }
181
182         for (Language *l = first_lang; l; l = l->next) {
183                 if (!strcasecmp(l->name, lang)) {
184                         output_lang = l;
185                         return;
186                 }
187         }
188         
189         fprintf(stderr, "Unsupported language \"%s\".\n", lang);
190         throw UserError();
191 }
192
193 static void set_target(const char *targ)
194 {
195         if (target != &targets[0]) {
196                 fprintf(stderr, "Only one target architecture may be specified.\n");
197                 throw UserError();
198         }
199         
200         for (int i = 1; i <= max_target; i++) {
201                 if (!strcasecmp(targ, targets[i].name)) {
202                         target = &targets[i];
203                         return;
204                 }
205         }
206
207         fprintf(stderr, "Unsupported target \"%s\".\n", targ);
208         throw UserError();
209 }
210
211 // Returns true if the argument is consumed.
212 static bool shortopt(char c, const char *arg)
213 {
214         switch (c) {
215                 case 'd':
216                         idl_debug = 1;
217                         cdl_debug = 1;
218                         break;
219
220                 case 'h':
221                         print_usage();
222                         exit(0);
223                         
224                 case 'i':
225                         if (!arg) {
226                                 fprintf(stderr, "The -i option requires an argument.\n");
227                                 throw UserError();
228                         }
229                         
230                         UserNameSpace::declare_import(arg);
231                         return true;
232                 
233                 case 'M':
234                         makedep = true;
235                         break;
236                 
237                 case 'n':
238                         no_output = true;
239                         break;
240                 
241                 case 'l':
242                         if (!arg) {
243                                 fprintf(stderr, "The -l option requires an argument.\n");
244                                 throw UserError();
245                         }
246
247                         set_lang(arg);
248                         return true;
249                 
250                 case 'o':
251                         if (output_dir) {
252                                 fprintf(stderr, "Only one output directory may be specified.\n");
253                                 throw UserError();
254                         }
255                 
256                         if (!arg) {
257                                 fprintf(stderr, "The -o option requires an argument.\n");
258                                 throw UserError();
259                         }
260
261                         output_dir = arg;
262                         return true;
263                 
264                 case 'r':
265                         server_stubs = true;
266                         break;
267
268                 case 's':
269                         if (output_ns_name) {
270                                 fprintf(stderr, "Only one output namespace may be specified.\n");
271                                 throw UserError();
272                         }
273                 
274                         output_ns_name = arg;
275                         return true;
276
277                 case 't':
278                         if (!arg) {
279                                 fprintf(stderr, "The -t option requires an argument.\n");
280                                 throw UserError();
281                         }
282                         
283                         set_target(arg);
284                         return true;
285
286                 default:
287                         fprintf(stderr, "%s: unknown option %c\n", cmdname, c);
288                         throw UserError();
289         }
290         
291         return false;
292 }
293
294 static void longopt(const char *s, const char *arg)
295 {
296         if (!strcmp(s, "help")) {
297                 print_usage();
298                 exit(0);
299         } else if (!strcmp(s, "debug")) {
300                 idl_debug = 1;
301                 cdl_debug = 1;
302         } else if (!strcmp(s, "include")) {
303                 if (!arg) {
304                         fprintf(stderr, "The --include option requires an argument.\n");
305                         throw UserError();
306                 }
307
308                 UserNameSpace::declare_import(arg);
309         } else if (!strcmp(s, "makedep")) {
310                 makedep = true;
311         } else if (!strcmp(s, "no-output")) {
312                 no_output = true;
313         } else if (!strcmp(s, "output")) {
314                 if (output_dir) {
315                         fprintf(stderr, "Only one output directory may be specified.\n");
316                         throw UserError();
317                 }
318
319                 if (!arg) {
320                         fprintf(stderr, "The --output option requires an argument.\n");
321                         throw UserError();
322                 }
323
324                 output_dir = arg;
325         } else if (!strcmp(s, "namespace")) {
326                 if (output_ns_name) {
327                         fprintf(stderr, "Only one output namespace may be specified.\n");
328                         throw UserError();
329                 }
330
331                 if (!arg) {
332                         fprintf(stderr, "The --namespace option requires an argument.\n");
333                         throw UserError();
334                 }
335         
336                 output_ns_name = arg;
337         } else if (!strcmp(s, "language")) {
338                 if (!arg) {
339                         fprintf(stderr, "The --language option requires an argument.\n");
340                         throw UserError();
341                 }
342
343                 set_lang(arg);
344         } else if (!strcmp(s, "target")) {
345                 if (!arg) {
346                         fprintf(stderr, "The --target option requires an argument.\n");
347                         throw UserError();
348                 }
349
350                 set_target(arg);
351         } else if (!strcmp(s, "show-languages")) {
352                 printf("Supported language bindings:\n");
353                 for (Language *l = first_lang; l; l = l->next)  
354                         printf("   %s\n", l->name);
355                 printf("\n");
356                 exit(0);
357         } else if (!strcmp(s, "show-targets")) {
358                 printf("Supported target architectures:\n");
359                 for (int i = 1; i <= max_target; i++)
360                         printf("   %s\n", targets[i].name);
361                 printf("\n");
362                 exit(0);
363         } else if (!strcmp(s, "server")) {
364                 server_stubs = true;
365         } else {
366                 fprintf(stderr, "%s: unknown option \"%s\"\n", cmdname, s);
367                 throw UserError();
368         }
369 }
370
371 static int global_argc;
372 static const char **global_argv;
373 static int got_dashdash;
374
375 static void process_args(void)
376 {
377         int i;
378         size_t j;
379         char *s;
380         
381         for (i = 1; i < global_argc; i++) {
382                 if (global_argv[i][0] == '-' && global_argv[i][1] && !got_dashdash) {
383                         const char *opt = global_argv[i];
384                 
385                         if (opt[1] == '-') {
386                                 if (!opt[2]) {
387                                         got_dashdash = 1;
388                                 } else {
389                                         s = strchr(&opt[2], '=');
390
391                                         if (!s)
392                                                 longopt(&opt[2], NULL);
393                                         else {
394                                                 *s=0;
395                                                 longopt(&opt[2], s+1);
396                                         }
397                                 }
398                         } else for (j = 1; j < strlen(opt); j++) {
399                                 if (shortopt(opt[j], global_argv[i + 1]))
400                                         i++;
401                         }
402                 } else {
403                         inputs.push_back(global_argv[i]);
404                 }
405         }
406 }
407
408 // Provide automatic closing of a file handle upon exception
409 struct FileHolder {
410         FILE *f;
411         
412         FileHolder()
413         {
414                 f = NULL;
415         }
416         
417         ~FileHolder()
418         {
419                 if (f)
420                         fclose(f);
421         }
422 };
423
424 void parse_inputs(bool cdl)
425 {
426         for (list<const char *>::iterator i = inputs.begin();
427              i != inputs.end(); ++i)
428         {
429                 FileHolder fh;
430                 cur_input_file = *i;
431
432                 curline = 1;
433                 
434                 if (strcmp(cur_input_file, "-")) {
435                         yyin = fh.f = fopen(cur_input_file, "r");
436                         if (!yyin) {
437                                 fprintf(stderr, "Cannot open input file \"%s\": %s\n",
438                                         cur_input_file, strerror(errno));
439                                 throw UserError();
440                         }
441                 } else {
442                         yyin = stdin;
443                         cur_input_file = "stdin";
444                 }
445                 
446                 if (cdl) {
447                         cur_nspace = cdl_toplevel;
448                         setup_cdlparse();
449                         
450                         if (cdl_parse())
451                                 throw UserError();
452                 } else {
453                         cur_nspace = output_ns;
454                         setup_idlparse();
455
456                         if (idl_parse())
457                                 throw UserError();
458                 }
459                 
460                 if (finish_lex() || num_err)
461                         throw UserError();
462         }
463         
464         cur_input_file = "<none>";
465         curline = 0;
466
467         if (!nspace_stack.empty())
468                 BUG();
469 }
470
471 static void init_output_ns()
472 {
473         StrList *strl;
474
475         try {
476                 String *str = new String(output_ns_name);
477                 strl = new StrList(str);
478         }
479
480         catch (InvalidArgument) {
481                 fprintf(stderr, "Output namespace \"%s\" is not vaild.\n",
482                         output_ns_name);
483                 throw UserError();
484         }
485
486         cur_nspace = toplevel;
487         NameSpace *new_ns = add_nspace(strl, false);
488
489         if (!new_ns)
490                 BUG();
491                 
492         NameSpace *conflict = check_for_imports(new_ns);
493         if (conflict) {         
494                 fprintf(stderr, "Output namespace \"%s\" conflicts"
495                                 " with \"%s\" at \"%s\".\n",
496                         output_ns_name, conflict->get_fq_name()->flatten()->c_str(),
497                         conflict->get_path()->c_str());
498
499                 throw UserError();
500         }
501
502         if (!new_ns)
503                 BUG();
504         output_ns = dynamic_cast<UserNameSpace *>(new_ns);
505         if (!output_ns)
506                 BUG();
507 }
508
509 void lookup_system_object()
510 {
511         try {
512                 StrList *sl = new StrList;
513                 
514                 sl->push_back(new String(""));
515                 sl->push_back(new String("System"));
516                 sl->push_back(new String("Object"));
517
518                 Symbol *sym = lookup_sym(toplevel, sl, toplevel);
519                 System_Object = dynamic_cast<Interface *>(sym);
520         }
521         
522         catch (UserError) {
523                 yyerrorf("Could not find System.Object.");
524                 yyerrorf("Be sure to include the file or directory containing "
525                          "the System namespace.");
526
527                 throw UserError();
528         }
529         
530         if (!System_Object) {
531                 yyerrorf("System.Object is not an interface.");
532                 throw UserError();
533         }
534 }
535
536 void lookup_system_vstruct()
537 {
538         try {
539                 StrList *sl = new StrList();
540                 
541                 sl->push_back(new String(""));
542                 sl->push_back(new String("System"));
543                 sl->push_back(new String("VStruct"));
544
545                 Symbol *sym = lookup_sym(toplevel, sl, toplevel);
546                 System_VStruct = dynamic_cast<Struct *>(sym);
547         }
548         
549         catch (UserError) {
550                 yyerrorf("Could not find System.VStruct.");
551                 yyerrorf("Be sure to include the file or directory containing "
552                          "the System namespace.");
553
554                 throw UserError();
555         }
556         
557         if (!System_VStruct) {
558                 yyerrorf("System.VStruct is not a struct.");
559                 throw UserError();
560         }
561         
562         if (!System_VStruct->is_virtual()) {
563                 yyerrorf("System.VStruct is not virtual.");
564                 throw UserError();
565         }
566 }
567
568 void normal_output()
569 {
570         if (inputs.empty()) {
571                 fprintf(stderr, "No inputs given.\n");
572                 print_usage();
573                 throw UserError();
574         }
575         
576         if (makedep) {
577                 fprintf(stderr, "Dependency generation is only supported "
578                                 "when generating language output.\n");
579                 throw UserError();
580         }
581         
582         if (!no_output && !output_dir) {
583                 fprintf(stderr, "An output directory must be specified "
584                                 "when not using -n.\n");
585                 throw UserError();
586         }
587
588         if (!output_ns_name) {
589                 fprintf(stderr, "An output namespace must be specified.\n");
590                 throw UserError();
591         }
592
593         if (!no_output && output_dir)
594                 makepath(output_dir);
595
596         init_output_ns();
597         
598         current_pass = 1;
599         autorelease_pool.clean();
600
601         parse_inputs(false);
602
603         current_pass = 2;
604         autorelease_pool.clean();
605
606         lookup_system_object();
607         lookup_system_vstruct();
608         output_ns->lookup_imports();
609         
610         current_pass = 3;
611         autorelease_pool.clean();
612         
613         output_ns->lookup_chain();
614         if (num_err)
615                 throw UserError();
616         
617         current_pass = 4;
618         autorelease_pool.clean();
619
620         output_ns->lookup_misc();
621         if (num_err)
622                 throw UserError();
623
624         current_pass = 5;
625         autorelease_pool.clean();
626
627         output_ns->final_analysis();
628         if (num_err)
629                 throw UserError();
630
631         current_pass = 6;
632         autorelease_pool.clean();
633         
634         if (!no_output)
635                 output_ns->output(output_dir);
636
637         autorelease_pool.clean();
638 }
639
640 void language_output()
641 {
642         if (server_stubs) {
643                 if (inputs.empty()) {
644                         fprintf(stderr, "No inputs given.\n");
645                         print_usage();
646                         throw UserError();
647                 }
648         } else {
649                 if (!inputs.empty()) {
650                         fprintf(stderr, "Inputs may not be specified when generating "
651                                         "language-specific client output.\n"
652                                         "Use --include to specify input namespaces.\n");
653                         throw UserError();
654                 }
655
656                 if (!output_ns_name) {
657                         fprintf(stderr, "An output namespace must be specified.\n");
658                         throw UserError();
659                 }
660
661                 if (makedep) {
662                         fprintf(stderr, "Dependency information is currently only supported "
663                                         "for server stubs.\n");
664                         throw UserError();
665                 }
666         }
667
668         if (no_output) {
669                 fprintf(stderr, "-n may not be used when generating "
670                                 "language-specific output.\n");
671                 throw UserError();
672         }
673
674         if (!output_dir) {
675                 fprintf(stderr, "An output directory must be specified when "
676                                 "generating language-specific output.\n");
677                 throw UserError();
678         }
679
680         if (!makedep && target == &targets[0]) {
681                 fprintf(stderr, "Target detection not yet implemented.\n"
682                                 "Please specify a target architecture.\n");
683                         throw UserError();
684         }
685
686         if (!makedep)
687                 makepath(output_dir);
688
689         if (server_stubs) {
690                 current_pass = INT_MAX;
691                 lookup_system_object();
692                 lookup_system_vstruct();
693                 parse_inputs(true);
694                 autorelease_pool.clean();
695                 output_lang->output_server(cdl_toplevel, output_dir);
696         } else {
697                 StrList *output_ns_strl;
698                 try {
699                         String *output_ns_str = new String(output_ns_name);
700                         output_ns_strl = new StrList(output_ns_str);
701                 }
702                 
703                 catch (InvalidArgument) {
704                         fprintf(stderr, "Output namespace \"%s\" is not vaild.\n",
705                                 output_ns_name);
706                         throw UserError();
707                 }
708                 
709                 cur_nspace = toplevel;
710                 current_pass = INT_MAX;
711                 lookup_system_object();
712                 lookup_system_vstruct();
713                 
714                 Symbol *sym = lookup_sym(toplevel, output_ns_strl, toplevel);
715                 output_ns = dynamic_cast<UserNameSpace *>(sym);
716                 if (!output_ns) {
717                         fprintf(stderr, "Output namespace \"%s\" is not a pure namespace.\n",
718                                 output_ns_name);
719                         throw UserError();
720                 }
721                 
722                 output_ns->import_all_recursive();
723                 autorelease_pool.clean();
724                 output_lang->output_root(output_ns, output_dir);
725         }
726
727         autorelease_pool.clean();
728 }
729
730 int run_idlc(int argc, const char **argv)
731 {
732         global_argc = argc;
733         global_argv = argv;
734         cmdname = argv[0];
735
736         toplevel = new UserNameSpace();
737         cdl_toplevel = new UserNameSpace();
738
739         try {
740                 process_args();
741                         
742                 if (output_lang)
743                         language_output();
744                 else {
745                         if (server_stubs) {
746                                 fprintf(stderr, "The -r (--server) option may only be used "
747                                                 "with the -l (--lang) option.\n");
748
749                                 throw UserError();
750                         }
751                 
752                         normal_output();
753                 }
754         }
755         
756         catch (InternalError &e) {
757                 fprintf(stderr, "Internal idlc error at %s:%d\n",
758                         e.file, e.line);
759                 return 1;
760         }
761         
762         catch (InvalidArgument) {
763                 fprintf(stderr, "Internal idlc error: Uncaught InvalidArgument\n");
764                 return 1;
765         }
766
767         catch (SymbolNotFound) {
768                 fprintf(stderr, "Internal idlc error: Uncaught SymbolNotFound\n");
769                 return 1;
770         }
771
772         catch (DuplicateSymbol) {
773                 fprintf(stderr, "Internal idlc error: Uncaught DuplicateSymbol\n");
774                 return 1;
775         }
776         
777         catch (UserError) {
778                 // An error message has already been displayed.
779                 num_err++;
780         }
781         
782         catch (...) {
783                 fprintf(stderr, "%s:%d: Internal error: Uncaught Exception\n",
784                         cur_input_file, curline);
785                 return 1;
786         }
787
788         if (num_err)
789                 return 1;
790
791         return 0;
792 }
793
794 int main(int argc, const char **argv)
795 {
796         int ret = run_idlc(argc, argv);
797         autorelease_pool.clean();
798         return ret;
799 }
800
801 extern "C" int yywrap()
802 {
803         return 1;
804 }
805
806 extern char *yytext;
807
808 void idl_error(char *s)
809 {
810         if (strlen(yytext))
811                 fprintf(stderr, "%s:%d: %s at \"%s\".\n", cur_input_file, curline, s, yytext);
812         else
813                 fprintf(stderr, "%s:%d: %s at end of input.\n", cur_input_file, curline, s);
814
815         num_err++;
816 }
817
818 void yyerrorf(const char *s, ...)
819 {
820         va_list va;
821         va_start(va, s);
822         fprintf(stderr, "%s:%d: ", cur_input_file, curline);
823         vfprintf(stderr, s, va);
824         fprintf(stderr, "\n");
825         va_end(va);
826         
827         num_err++;
828 }
829
830 void yyerrorfl(const char *file, int line, const char *s, ...)
831 {
832         va_list va;
833         va_start(va, s);
834         fprintf(stderr, "%s:%d: ", file, line);
835         vfprintf(stderr, s, va);
836         fprintf(stderr, "\n");
837         va_end(va);
838         
839         num_err++;
840 }
841
842 int idl_lex()
843 {
844         return yylex();
845 }