1%{
2/*
3 *  FILE: parser.y
4 *  AUTH: Michael John Radwin <mjr@acm.org>
5 *
6 *  DESC: stubgen grammar description.  Portions borrowed from
7 *  Newcastle University's Arjuna project (http://arjuna.ncl.ac.uk/),
8 *  and Jeff Lee's ANSI Grammar
9 *  (ftp://ftp.uu.net/usenet/net.sources/ansi.c.grammar.Z)
10 *  This grammar is only a subset of the real C++ language.
11 *
12 *  DATE: Thu Aug 15 13:10:06 EDT 1996
13 *   $Id: parser.y 10 2002-07-09 12:24:59Z ejakowatz $
14 *
15 *  Copyright (c) 1996-1998  Michael John Radwin
16 *
17 *  This program is free software; you can redistribute it and/or modify
18 *  it under the terms of the GNU General Public License as published by
19 *  the Free Software Foundation; either version 2 of the License, or
20 *  (at your option) any later version.
21 *
22 *  This program is distributed in the hope that it will be useful,
23 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
24 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 *  GNU General Public License for more details.
26 *
27 *  You should have received a copy of the GNU General Public License
28 *  along with this program; if not, write to the Free Software
29 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30 *
31 *  --------------------------------------------------------------------
32 *
33 *  $Log: parser.y,v $
34 *  Revision 1.1  2002/07/09 12:24:59  ejakowatz
35 *  It is accomplished ...
36 *
37 *  Revision 1.1  2001/11/07 10:06:07  ithamar
38 *  Added stubgen to CVS
39 *
40 *  Revision 1.72  1998/07/07 00:14:06  mradwin
41 *  removed extra space from throw_decl, cleaned up memory leak
42 *  in ctor skeleton
43 *
44 *  Revision 1.71  1998/06/11 14:52:09  mradwin
45 *  allow for empty class declarations, such as
46 *  class Element {};
47 *  also, differentiate structs from classes with
48 *  new STRUCT_KIND tag.
49 *  New version: 2.04
50 *
51 *  Revision 1.70  1998/05/11 19:49:11  mradwin
52 *  Version 2.03 (updated copyright information).
53 *
54 *  Revision 1.69  1998/04/07 23:43:34  mradwin
55 *  changed error-handling code significantly.
56 *  several functions now return a value, and instead of
57 *  calling fatal(), we do a YYABORT or YYERROR to get out
58 *  of the parsing state.
59 *  New version: 2.02.
60 *
61 *  Revision 1.68  1998/03/28 02:59:41  mradwin
62 *  working on slightly better error recovery; not done yet.
63 *
64 *  Revision 1.67  1998/03/28 02:34:56  mradwin
65 *  added multi-line function parameters
66 *  also changed pointer and reference (* and &) types so there
67 *  is no trailing space before the parameter name.
68 *
69 *  Revision 1.66  1998/01/12 19:39:11  mradwin
70 *  modified rcsid
71 *
72 *  Revision 1.65  1997/11/13 22:50:55  mradwin
73 *  moved copyright from parser.y to main.c
74 *
75 *  Revision 1.64  1997/11/13 22:40:15  mradwin
76 *  fixed a silly comment bug
77 *
78 *  Revision 1.63  1997/11/13 22:37:31  mradwin
79 *  changed char[] to char * to make non-gcc compilers
80 *  a little happier.  We need to #define const to nothing
81 *  for other compilers as well.
82 *
83 *  Revision 1.62  97/11/13  21:29:30  21:29:30  mradwin (Michael Radwin)
84 *  moved code from parser.y to main.c
85 *
86 *  Revision 1.61  1997/11/13 21:10:17  mradwin
87 *  renamed stubgen.[ly] to parser.y lexer.l
88 *
89 *  Revision 1.60  1997/11/11 04:11:29  mradwin
90 *  fixed command-line flags: invalid options now force usgage.
91 *
92 *  Revision 1.59  1997/11/11 04:03:56  mradwin
93 *  changed version info
94 *
95 *  Revision 1.58  1997/11/11 03:54:05  mradwin
96 *  fixed a long-standing bug with -b option.  a typo was causing
97 *  the -b flag to be ignored.
98 *
99 *  Revision 1.57  1997/11/11 03:52:06  mradwin
100 *  changed fatal()
101 *
102 *  Revision 1.56  1997/11/05 03:02:02  mradwin
103 *  Modified logging routines.
104 *
105 *  Revision 1.55  1997/11/05 02:14:38  mradwin
106 *  Made some compiler warnings disappear.
107 *
108 *  Revision 1.54  1997/11/01 23:26:13  mradwin
109 *  new Revision string and usage info
110 *
111 *  Revision 1.53  1997/11/01 23:12:43  mradwin
112 *  greatly improved error-recovery.  errors no longer spill over
113 *  into other files because the yyerror state is properly reset.
114 *
115 *  Revision 1.52  1997/10/27 01:14:23  mradwin
116 *  fixed constant_value so it supports simple arithmetic.  it's
117 *  not as robust as full expressions, but this will handle the
118 *  char buffer[BUFSIZE + 1] problem.
119 *
120 *  Also removed expansion rules that simply did { $$ = $1; } because
121 *  that action is implicit anyway.
122 *
123 *  Revision 1.51  1997/10/26 23:16:32  mradwin
124 *  changed inform_user and fatal functions to use varargs
125 *
126 *  Revision 1.50  1997/10/26 22:27:07  mradwin
127 *  Fixed this bug:
128 *  stubgen dies on the following because the protected section is empty:
129 *
130 *  class WidgetCsg : public WidgetLens {
131 *   protected:
132 *
133 *   public:
134 *       virtual ~WidgetCsg() {}
135 *                WidgetCsg();
136 *  };
137 *
138 *  Error:
139 *  stubgen version 2.0-beta $Revision: 1.1 $.
140 *  parse error at line 4, file test.H:
141 *   public:
142 *        ^
143 *
144 *  Revision 1.49  1997/10/16 19:42:48  mradwin
145 *  added support for elipses, static member/array initializers,
146 *  and bitfields.
147 *
148 *  Revision 1.48  1997/10/16 17:35:39  mradwin
149 *  cleaned up usage info
150 *
151 *  Revision 1.47  1997/10/16 17:12:59  mradwin
152 *  handle extern "C" blocks better now, and support multi-line
153 *  macros.  still need error-checking.
154 *
155 *  Revision 1.46  1997/10/15 22:09:06  mradwin
156 *  changed tons of names.  stubelem -> sytaxelem,
157 *  stubin -> infile, stubout -> outfile, stublog -> logfile.
158 *
159 *  Revision 1.45  1997/10/15 21:33:36  mradwin
160 *  fixed up function_hdr
161 *
162 *  Revision 1.44  1997/10/15 21:33:02  mradwin
163 *  *** empty log message ***
164 *
165 *  Revision 1.43  1997/10/15 17:42:37  mradwin
166 *  added support for 'extern "C" { ... }' blocks.
167 *
168 *  Revision 1.42  1997/09/26 20:59:18  mradwin
169 *  now allow "struct foobar *f" to appear in a parameter
170 *  list or as a variable decl.  Had to remove the
171 *  class_or_struct rule and blow up the class_specifier
172 *  description.
173 *
174 *  Revision 1.41  1997/09/26 19:02:18  mradwin
175 *  fixed memory leak involving template decls in skeleton code.
176 *  Leads me to believe that skel_elemcmp() is flawed, because
177 *  it may rely in parent->templ info.
178 *
179 *  Revision 1.40  1997/09/26 18:44:22  mradwin
180 *  changed parameter handing from char *'s to an argument type
181 *  to facilitate comparisons between skeleton code
182 *  and header code.  Now we can correctly recognize different
183 *  parameter names while still maintaining the same signature.
184 *
185 *  Revision 1.39  1997/09/26 00:47:29  mradwin
186 *  added better base type support -- recognize things like
187 *  "long long" and "short int" now.
188 *
189 *  Revision 1.38  1997/09/19 18:16:37  mradwin
190 *  allowed an instance name to come after a class, struct,
191 *  union, or enum.  This improves parseability of typedefs
192 *  commonly found in c header files, although true typedefs are
193 *  not understood.
194 *
195 *  Revision 1.37  1997/09/15 22:38:28  mradwin
196 *  did more revision on the SGDEBUG stuff
197 *
198 *  Revision 1.36  1997/09/15 19:05:26  mradwin
199 *  allow logging to be compiled out by turning off SGDEBUG
200 *
201 *  Revision 1.35  1997/09/12 00:58:43  mradwin
202 *  duh, silly me.  messed up compilation.
203 *
204 *  Revision 1.34  1997/09/12 00:57:49  mradwin
205 *  Revision string inserted in usage
206 *
207 *  Revision 1.33  1997/09/12 00:51:19  mradwin
208 *  string copyright added to code for binary copyright.
209 *
210 *  Revision 1.32  1997/09/12 00:47:21  mradwin
211 *  some more compactness of grammar with parameter_list_opt
212 *  and also ampersand_opt
213 *
214 *  Revision 1.31  1997/09/12 00:26:19  mradwin
215 *  better template support, but still poor
216 *
217 *  Revision 1.30  1997/09/08 23:24:51  mradwin
218 *  changes to error-handling code.
219 *  also got rid of the %type <flag> for the top-level rules
220 *
221 *  Revision 1.30  1997/09/08 23:20:02  mradwin
222 *  some error reporting changes and default values for top-level
223 *  grammar stuff.
224 *
225 *  Revision 1.29  1997/09/08 17:54:24  mradwin
226 *  cleaned up options and usage info.
227 *
228 *  Revision 1.28  1997/09/05 19:38:04  mradwin
229 *  changed options for .ext instead of -l or -x
230 *
231 *  Revision 1.27  1997/09/05 19:17:06  mradwin
232 *  works for scanning old versions, except for parameter
233 *  names that differ between .H and .C files.
234 *
235 *  Revision 1.26  1997/09/05 16:34:36  mradwin
236 *  GPL-ized code.
237 *
238 *  Revision 1.25  1997/09/05 16:11:44  mradwin
239 *  some simple cleanup before GPL-izing the code
240 *
241 *  Revision 1.24  1997/09/04 19:50:34  mradwin
242 *  whoo-hoo!  by blowing up the description
243 *  exponentially, it works!
244 *
245 *  Revision 1.23  1997/03/20 16:05:41  mjr
246 *  renamed syntaxelem to syntaxelem_t, cleaned up throw_decl
247 *
248 *  Revision 1.22  1996/10/02 15:16:57  mjr
249 *  using pathname.h instead of libgen.h
250 *
251 *  Revision 1.21  1996/09/12 14:44:49  mjr
252 *  Added throw decl recognition (great, another 4 bytes in syntaxelem)
253 *  and cleaned up the grammar so that const_opt appears in far fewer
254 *  places.  const_opt is by default 0 as well, so we don't need to
255 *  pass it as an arg to new_elem().
256 *
257 *  I also added a fix to a potential bug with the MINIT and INLIN
258 *  exclusive start states.  I think they could have been confused
259 *  by braces within comments, so now I'm grabbing comments in those
260 *  states as well.
261 *
262 *  Revision 1.20  1996/09/12 04:55:22  mjr
263 *  changed expand strategy.  Don't expand while parsing now;
264 *  enqueue as we go along and expand at the end.  Eventually
265 *  we'll need to provide similar behavior for when we parse
266 *  .C files
267 *
268 *  Revision 1.19  1996/09/12 03:46:10  mjr
269 *  No concrete changes in code.  Just added some sanity by
270 *  factoring out code into util.[ch] and putting some prototypes
271 *  that were in table.h into stubgen.y where they belong.
272 *
273 *  Revision 1.18  1996/09/06 14:32:48  mjr
274 *  defined the some_KIND constants for clarity, and made
275 *  expandClass return immediately if it was give something other
276 *  than a CLASS_KIND element.
277 *
278 *  Revision 1.17  1996/09/06 14:05:44  mjr
279 *  Almost there with expanded operator goodies.  Still need
280 *  to get OPERATOR type_name to work.
281 *
282 *  Revision 1.16  1996/09/04 22:28:09  mjr
283 *  nested classes work and default arguments are now removed
284 *  from the parameter lists.
285 *
286 *  Revision 1.15  1996/09/04 20:01:57  mjr
287 *  non-functional expanded code.  needs work.
288 *
289 *  Revision 1.14  1996/09/01 21:29:34  mjr
290 *  put the expanded_operator code back in as a useless rule.
291 *  oughta think about fixing it up if possible
292 *
293 *  Revision 1.13  1996/09/01 20:59:48  mjr
294 *  Added collectMemberInitList() function, which is similar
295 *  to collectInlineDef() and also the exclusive state MINIT
296 *
297 *  Revision 1.12  1996/08/23 05:09:19  mjr
298 *  fixed up some more portability things
299 *
300 *  Revision 1.11  1996/08/22 02:43:47  mjr
301 *  added parse error message (using O'Reilly p. 274)
302 *
303 *  Revision 1.10  1996/08/21 18:33:50  mjr
304 *  added support for template instantiation in the type_name
305 *  rule.  surprisingly it didn't cause any shift/reduce conflicts.
306 *
307 *  Revision 1.9  1996/08/21 17:40:56  mjr
308 *  added some cpp directives for porting to WIN32
309 *
310 *  Revision 1.8  1996/08/21 00:00:19  mjr
311 *  approaching stability and usability.  command line arguments
312 *  are handled now and the fopens and fcloses appear to work.
313 *
314 *  Revision 1.7  1996/08/20 20:44:23  mjr
315 *  added initial support for optind but it is incomplete.
316 *
317 *  Revision 1.6  1996/08/19 17:14:59  mjr
318 *  misordered args, fixed bug
319 *
320 *  Revision 1.5  1996/08/19 17:11:41  mjr
321 *  RCS got confused with the RCS-style header goodies.
322 *  got it cleaned up now.
323 *
324 *  Revision 1.4  1996/08/19 17:01:33  mjr
325 *  Removed the expanded code checking and added
326 *  lots of code that duplicates what stubgen.pl did.
327 *  still need options pretty badly
328 *
329 *  Revision 1.3  1996/08/17 23:21:10  mjr
330 *  added the expanded operator code, cleaned up tabs.
331 *  consider putting all of the expanded code in another
332 *  grammar - this one is getting cluttered.
333 *
334 */
335%}
336
337%{
338#include "table.h"
339#include "util.h"
340#include <string.h>
341#include <stdlib.h>
342#include <stdio.h>
343
344#ifdef WIN32
345#include <malloc.h> /* defintion of alloca */
346#include "getopt.h" /* use GNU getopt      */
347#endif /* WIN32 */
348
349#ifndef WIN32
350#include <pwd.h>
351#endif /* WIN32 */
352
353/* defined in lexer.l */
354extern int collectInlineDef();
355extern int collectMemberInitList();
356
357/* defined here in parser.y */
358static int error_recovery();
359static int yyerror(char *);
360static const char rcsid[] = "$Id: parser.y 10 2002-07-09 12:24:59Z ejakowatz $";
361
362/* defined in main.c */
363extern FILE *outfile;
364extern char *currentFile;
365extern int lineno;
366
367%}
368
369%union {
370  char *string;
371  syntaxelem_t *elt;
372  arg_t *arg;
373  int flag;
374}
375
376%token <string> IDENTIFIER CONSTANT STRING_LITERAL
377%token <string> CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE VOID
378%token NEW DELETE TEMPLATE THROW
379
380%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP
381%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
382%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
383%token XOR_ASSIGN OR_ASSIGN CLCL MEM_PTR_OP
384
385%token FRIEND OPERATOR CONST CLASS STRUCT UNION ENUM
386%token PROTECTED PRIVATE PUBLIC EXTERN ELIPSIS
387
388%type <string> simple_type_name simple_signed_type non_reference_type
389%type <string> scoped_identifier pointer asterisk
390%type <string> type_name binary_operator
391%type <string> assignment_operator unary_operator any_operator
392%type <string> variable_specifier_list union_specifier
393%type <string> constant_value multiple_variable_specifier
394%type <string> enum_specifier enumerator_list enumerator
395%type <string> template_specifier template_arg template_arg_list
396%type <string> template_instance_arg template_instance_arg_list
397%type <string> throw_decl throw_list variable_name bitfield_savvy_identifier
398%type <string> primary_expression expression
399%type <string> multiplicative_expression additive_expression
400%type <flag> const_opt ampersand_opt
401%type <elt> class_specifier
402%type <elt> member_func_specifier function_specifier constructor
403%type <elt> destructor member_specifier member member_with_access
404%type <elt> mem_type_specifier member_or_error
405%type <elt> member_list member_list_opt
406%type <elt> member_func_inlined type_specifier overloaded_op_specifier
407%type <elt> member_func_skel member_func_skel_spec
408%type <elt> constructor_skeleton destructor_skeleton
409%type <elt> overloaded_op_skeleton function_skeleton
410%type <arg> variable_or_parameter variable_specifier
411%type <arg> parameter_list parameter_list_opt unnamed_parameter
412
413
414%start translation_unit
415%%
416
417translation_unit
418	: declaration
419	| translation_unit declaration
420	;
421
422declaration
423	: declaration_specifiers ';'
424	| EXTERN STRING_LITERAL compound_statement
425{
426  log_printf("IGNORING extern \"C\" { ... } block.\n");
427  free($2);
428}
429	| member_func_inlined
430{
431    $1->kind = INLINED_KIND;
432    log_printf("\nBEGIN matched dec : m_f_i rule --");
433    print_se($1);
434    log_printf("END   matched dec : m_f_i rule\n");
435}
436	| function_skeleton
437{
438    $1->kind = SKEL_KIND;
439    log_printf("\nBEGIN matched dec : function_skeleton rule --");
440    print_se($1);
441    enqueue_skeleton($1);
442    log_printf("END   matched dec : function_skeleton rule\n");
443}
444	| ';'
445	| error
446{
447  log_printf("declaration : error.  Attempting to recover...\n");
448  yyerrok;
449  yyclearin;
450  if (error_recovery() != 0) {
451      log_printf("ERROR recovery could not complete -- YYABORT.\n");
452      YYABORT;
453  }
454  log_printf("ERROR recovery complete.\n");
455}
456	;
457
458declaration_specifiers
459	: member_specifier
460{
461    /* the name of the rule "member_specifier" might be misleading, but
462     * this is either a class, struct, union, enum, global var, global
463     * prototype, etc..  */
464    if ($1->kind == CLASS_KIND || $1->kind == STRUCT_KIND) {
465	enqueue_class($1);
466    } else {
467	log_printf("\nIGNORING      dec_spec : mem_spec (%s) --",
468		  string_kind($1->kind));
469	print_se($1);
470	log_printf("END IGNORING  dec_spec : mem_spec (%s)\n",
471		  string_kind($1->kind));
472    }
473}
474	| forward_decl
475	;
476
477type_specifier
478	: union_specifier
479{
480  /* ret_type, name, args, kind */
481  syntaxelem_t *elem = new_elem(strdup(""), $1, NULL, IGNORE_KIND);
482/*   print_se(elem); */
483  $$ = elem;
484}
485	| enum_specifier
486{
487  /* ret_type, name, args, kind */
488  syntaxelem_t *elem = new_elem(strdup(""), $1, NULL, IGNORE_KIND);
489/*   print_se(elem); */
490  $$ = elem;
491}
492	| class_specifier
493	;
494
495ampersand_opt
496	: /* nothing */				{ $$ = 0; }
497	| '&'					{ $$ = 1; }
498	;
499
500type_name
501	: non_reference_type ampersand_opt
502{
503  char *tmp_str = (char *) malloc(strlen($1) + ($2 ? 2 : 0) + 1);
504  strcpy(tmp_str, $1);
505  if ($2)
506    strcat(tmp_str, " &");
507  free($1);
508  $$ = tmp_str;
509}
510	| CONST non_reference_type ampersand_opt
511{
512  char *tmp_str = (char *) malloc(strlen($2) + ($3 ? 2 : 0) + 7);
513  sprintf(tmp_str, "const %s%s", $2, ($3 ? " &" : ""));
514  free($2);
515  $$ = tmp_str;
516}
517	;
518
519forward_decl
520	: CLASS IDENTIFIER			{ free($2); }
521	| CLASS scoped_identifier		{ free($2); }
522	| STRUCT IDENTIFIER			{ free($2); }
523	| STRUCT scoped_identifier		{ free($2); }
524	;
525
526non_reference_type
527	: scoped_identifier
528	| IDENTIFIER
529	| STRUCT IDENTIFIER
530{
531  char *tmp_str = (char *) malloc(strlen($2) + 8);
532  strcpy(tmp_str, "struct ");
533  strcat(tmp_str, $2);
534  free($2);
535  $$ = tmp_str;
536}
537	| scoped_identifier '<' template_instance_arg_list '>'
538{
539  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
540  sprintf(tmp_str, "%s<%s>", $1, $3);
541  free($1);
542  free($3);
543  $$ = tmp_str;
544}
545	| IDENTIFIER '<' template_instance_arg_list '>'
546{
547  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
548  sprintf(tmp_str, "%s<%s>", $1, $3);
549  free($1);
550  free($3);
551  $$ = tmp_str;
552}
553	| scoped_identifier '<' template_instance_arg_list '>' pointer
554{
555  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + strlen($5) + 4);
556  sprintf(tmp_str, "%s<%s> %s", $1, $3, $5);
557  free($1);
558  free($3);
559  free($5);
560  $$ = tmp_str;
561}
562	| IDENTIFIER '<' template_instance_arg_list '>' pointer
563{
564  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + strlen($5) + 4);
565  sprintf(tmp_str, "%s<%s> %s", $1, $3, $5);
566  free($1);
567  free($3);
568  free($5);
569  $$ = tmp_str;
570}
571	| scoped_identifier pointer
572{
573  char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2);
574  sprintf(tmp_str, "%s %s", $1, $2);
575  free($1);
576  free($2);
577  $$ = tmp_str;
578}
579	| IDENTIFIER pointer
580{
581  char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2);
582  sprintf(tmp_str, "%s %s", $1, $2);
583  free($1);
584  free($2);
585  $$ = tmp_str;
586}
587	| STRUCT IDENTIFIER pointer
588{
589  char *tmp_str = (char *) malloc(strlen($2) + strlen($3) + 9);
590  sprintf(tmp_str, "struct %s %s", $2, $3);
591  free($2);
592  free($3);
593  $$ = tmp_str;
594}
595	| simple_signed_type
596	| simple_signed_type pointer
597{
598  char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2);
599  sprintf(tmp_str, "%s %s", $1, $2);
600  free($1);
601  free($2);
602  $$ = tmp_str;
603}
604	;
605
606simple_signed_type
607	: simple_type_name
608	| SIGNED simple_type_name
609{
610  char *tmp_str = (char *) malloc(strlen($2) + 8);
611  strcpy(tmp_str,"signed ");
612  strcat(tmp_str, $2);
613  free($1);
614  free($2);
615  $$ = tmp_str;
616}
617	| UNSIGNED simple_type_name
618{
619  char *tmp_str = (char *) malloc(strlen($2) + 10);
620  strcpy(tmp_str,"unsigned ");
621  strcat(tmp_str, $2);
622  free($1);
623  free($2);
624  $$ = tmp_str;
625}
626	;
627
628simple_type_name
629	: CHAR
630	| SHORT
631	| SHORT INT
632{
633  $$ = strdup("short int");
634  free($1);
635  free($2);
636}
637	| INT
638	| LONG
639	| LONG INT
640{
641  $$ = strdup("long int");
642  free($1);
643  free($2);
644}
645	| LONG LONG
646{
647  $$ = strdup("long long");
648  free($1);
649  free($2);
650}
651	| LONG LONG INT
652{
653  $$ = strdup("long long int");
654  free($1);
655  free($2);
656  free($3);
657}
658	| UNSIGNED
659	| FLOAT
660	| DOUBLE
661	| VOID
662	;
663
664scoped_identifier
665	: IDENTIFIER CLCL IDENTIFIER
666{
667  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
668  sprintf(tmp_str, "%s::%s", $1, $3);
669  free($1);
670  free($3);
671  $$ = tmp_str;
672}
673	| scoped_identifier CLCL IDENTIFIER
674{
675  /* control-Y programming! */
676  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
677  sprintf(tmp_str, "%s::%s", $1, $3);
678  free($1);
679  free($3);
680  $$ = tmp_str;
681}
682	;
683
684pointer
685	: asterisk
686	| pointer asterisk
687{
688  char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 1);
689  strcpy(tmp_str,$1);
690  strcat(tmp_str,$2);
691  free($1);
692  free($2);
693  $$ = tmp_str;
694}
695	;
696
697asterisk
698	: '*'					{ $$ = strdup("*"); }
699	| '*' CONST				{ $$ = strdup("*const "); }
700	;
701
702variable_or_parameter
703	: type_name bitfield_savvy_identifier
704{
705  arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
706  new_arg->type = $1;
707  new_arg->name = $2;
708  new_arg->array = NULL;
709  new_arg->next = NULL;
710  $$ = new_arg;
711}
712	| type_name scoped_identifier
713{
714  arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
715  new_arg->type = $1;
716  new_arg->name = $2;
717  new_arg->array = NULL;
718  new_arg->next = NULL;
719  $$ = new_arg;
720}
721	| variable_or_parameter '[' constant_value ']'
722{
723  char *old_array = $1->array;
724  int old_len = old_array ? strlen(old_array) : 0;
725  $1->array = (char *) malloc(strlen($3) + old_len + 3);
726  sprintf($1->array, "%s[%s]", old_array ? old_array : "", $3);
727  free($3);
728  if (old_array)
729    free(old_array);
730  $$ = $1;
731}
732	| variable_or_parameter '[' ']'
733{
734  char *old_array = $1->array;
735  int old_len = old_array ? strlen(old_array) : 0;
736  $1->array = (char *) malloc(old_len + 3);
737  sprintf($1->array, "%s[]", old_array ? old_array : "");
738  if (old_array)
739    free(old_array);
740  $$ = $1;
741}
742	;
743
744bitfield_savvy_identifier
745	: IDENTIFIER
746	| IDENTIFIER ':' CONSTANT		{ free($3); $$ = $1;}
747	;
748
749variable_name
750	: bitfield_savvy_identifier
751	| pointer IDENTIFIER
752{
753  char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2);
754  sprintf(tmp_str, "%s %s", $1, $2);
755  free($1);
756  free($2);
757  $$ = tmp_str;
758}
759	| variable_name '[' constant_value ']'
760{
761  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
762  sprintf(tmp_str, "%s[%s]", $1, $3);
763  free($1);
764  free($3);
765  $$ = tmp_str;
766}
767	| variable_name '[' ']'
768{
769  char *tmp_str = (char *) malloc(strlen($1) + 3);
770  strcpy(tmp_str, $1);
771  strcat(tmp_str, "[]");
772  free($1);
773  $$ = tmp_str;
774}
775	;
776
777variable_specifier
778	: variable_or_parameter
779	| EXTERN variable_or_parameter		{ $$ = $2; }
780	| variable_or_parameter '=' constant_value
781{
782  free($3);
783  $$ = $1;
784}
785	;
786
787multiple_variable_specifier
788	: variable_specifier
789{
790  $$ = args_to_string($1, 0);
791  free_args($1);
792}
793	| multiple_variable_specifier ',' variable_name
794{
795  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
796  sprintf(tmp_str, "%s, %s", $1, $3);
797  free($1);
798  free($3);
799  $$ = tmp_str;
800}
801	;
802
803variable_specifier_list
804	: multiple_variable_specifier ';'
805{
806  char *tmp_str = (char *) malloc(strlen($1) + 2);
807  sprintf(tmp_str, "%s;", $1);
808  free($1);
809  $$ = tmp_str;
810}
811	| variable_specifier_list multiple_variable_specifier ';'
812{
813  char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 3);
814  sprintf(tmp_str, "%s\n%s;", $1, $2);
815  free($1);
816  free($2);
817  $$ = tmp_str;
818}
819	;
820
821parameter_list_opt
822	: /* nothing */
823{
824  $$ = NULL;
825}
826	| parameter_list
827{
828  $$ = reverse_arg_list($1);
829}
830	| parameter_list ',' ELIPSIS
831{
832  arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
833  new_arg->type = strdup("...");
834  new_arg->name = NULL;
835  new_arg->array = NULL;
836  new_arg->next = $1;
837  $$ = reverse_arg_list(new_arg);
838}
839	| ELIPSIS
840{
841  arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
842  new_arg->type = strdup("...");
843  new_arg->name = NULL;
844  new_arg->array = NULL;
845  new_arg->next = NULL;
846  $$ = new_arg;
847}
848	;
849
850parameter_list
851	: variable_specifier
852	| unnamed_parameter
853	| parameter_list ',' variable_specifier
854{
855  $3->next = $1;
856  $$ = $3;
857}
858	| parameter_list ',' unnamed_parameter
859{
860  $3->next = $1;
861  $$ = $3;
862}
863	;
864
865unnamed_parameter
866	: type_name
867{
868  arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
869  new_arg->type = $1;
870  new_arg->name = NULL;
871  new_arg->array = NULL;
872  new_arg->next = NULL;
873  $$ = new_arg;
874}
875	| type_name '=' constant_value
876{
877  arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
878  new_arg->type = $1;
879  new_arg->name = NULL;
880  new_arg->array = NULL;
881  new_arg->next = NULL;
882  free($3);
883  $$ = new_arg;
884}
885	| unnamed_parameter '[' constant_value ']'
886{
887  char *old_array = $1->array;
888  int old_len = old_array ? strlen(old_array) : 0;
889  $1->array = (char *) malloc(strlen($3) + old_len + 3);
890  sprintf($1->array, "%s[%s]", old_array ? old_array : "", $3);
891  free($3);
892  if (old_array)
893    free(old_array);
894  $$ = $1;
895}
896	| unnamed_parameter '[' ']'
897{
898  char *old_array = $1->array;
899  int old_len = old_array ? strlen(old_array) : 0;
900  $1->array = (char *) malloc(old_len + 3);
901  sprintf($1->array, "%s[]", old_array ? old_array : "");
902  if (old_array)
903    free(old_array);
904  $$ = $1;
905}
906	;
907
908function_skeleton
909	: member_func_skel compound_statement
910	| constructor_skeleton ':'
911	  { if (collectMemberInitList() != 0) YYERROR; } compound_statement
912	| template_specifier member_func_skel compound_statement
913{
914  /* I think this is the correct behavior, but skel_elemcmp is wrong */
915  /* $2->templ = $1; */
916  free($1);
917  $$ = $2;
918}
919	| template_specifier constructor_skeleton ':'
920	  { if (collectMemberInitList() != 0) YYERROR; } compound_statement
921{
922  /* I think this is the correct behavior, but skel_elemcmp is wrong */
923  /* $2->templ = $1; */
924  free($1);
925  $$ = $2;
926}
927	;
928
929member_func_inlined
930	: member_func_specifier compound_statement
931	| constructor ':'
932	  { if (collectMemberInitList() != 0) YYERROR; } compound_statement
933	;
934
935member_func_skel
936	: member_func_skel_spec const_opt throw_decl
937{
938    $1->const_flag = $2;
939    $1->throw_decl = $3;
940    $$ = $1;
941}
942	| constructor_skeleton
943	| destructor_skeleton
944	;
945
946member_func_specifier
947	: function_specifier const_opt throw_decl
948{
949    $1->const_flag = $2;
950    $1->throw_decl = $3;
951    $$ = $1;
952}
953	| constructor
954	| destructor
955	;
956
957
958member_func_skel_spec
959	: type_name scoped_identifier '(' parameter_list_opt ')'
960{
961  /* ret_type, name, args, kind */
962  syntaxelem_t *elem = new_elem($1, $2, $4, FUNC_KIND);
963/*  print_se(elem); */
964  $$ = elem;
965}
966	| type_name IDENTIFIER '<' template_instance_arg_list '>' CLCL IDENTIFIER '(' parameter_list_opt ')'
967{
968  /* ret_type, name, args, kind */
969  syntaxelem_t *elem = new_elem($1,
970			      (char *) malloc(strlen($2) + strlen($4) + strlen($7) + 5),
971			      $9, FUNC_KIND);
972  sprintf(elem->name,"%s<%s>::%s", $2, $4, $7);
973  free($2);
974  free($4);
975  free($7);
976  $$ = elem;
977}
978	| overloaded_op_skeleton
979	;
980
981
982
983function_specifier
984	: type_name IDENTIFIER '(' parameter_list_opt ')'
985{
986  /* ret_type, name, args, kind */
987  syntaxelem_t *elem = new_elem($1, $2, $4, FUNC_KIND);
988  print_se(elem);
989  $$ = elem;
990}
991	| overloaded_op_specifier
992	;
993
994overloaded_op_skeleton
995	: type_name scoped_identifier CLCL OPERATOR any_operator '(' parameter_list_opt ')'
996{
997  /* ret_type, name, args, kind */
998  syntaxelem_t *elem = new_elem($1, (char *)malloc(strlen($2) + strlen($5) + 12),
999			      $7, FUNC_KIND);
1000  sprintf(elem->name, "%s::operator%s", $2, $5);
1001  free($2);
1002  free($5);
1003/*  print_se(elem); */
1004  $$ = elem;
1005}
1006	| scoped_identifier CLCL OPERATOR type_name '(' ')'
1007{
1008  /* ret_type, name, args, kind */
1009  syntaxelem_t *elem = new_elem(strdup(""),
1010			      (char *)malloc(strlen($1) + strlen($4) + 13),
1011			      NULL, FUNC_KIND);
1012  sprintf(elem->name, "%s::operator %s", $1, $4);
1013  free($1);
1014  free($4);
1015/*  print_se(elem); */
1016  $$ = elem;
1017}
1018	| type_name IDENTIFIER CLCL OPERATOR any_operator '(' parameter_list_opt ')'
1019{
1020  /* ret_type, name, args, kind */
1021  syntaxelem_t *elem = new_elem($1, (char *)malloc(strlen($2) + strlen($5) + 12),
1022			      $7, FUNC_KIND);
1023  sprintf(elem->name, "%s::operator%s", $2, $5);
1024  free($2);
1025  free($5);
1026/*  print_se(elem); */
1027  $$ = elem;
1028}
1029	| IDENTIFIER CLCL OPERATOR type_name '(' ')'
1030{
1031  /* ret_type, name, args, kind */
1032  syntaxelem_t *elem = new_elem(strdup(""),
1033			      (char *)malloc(strlen($1) + strlen($4) + 13),
1034			      NULL, FUNC_KIND);
1035  sprintf(elem->name, "%s::operator %s", $1, $4);
1036  free($1);
1037  free($4);
1038/*  print_se(elem); */
1039  $$ = elem;
1040}
1041	;
1042
1043overloaded_op_specifier
1044	: type_name OPERATOR any_operator '(' parameter_list_opt ')'
1045{
1046  /* ret_type, name, args, kind */
1047  syntaxelem_t *elem = new_elem($1, (char *)malloc(strlen($3) + 9),
1048			      $5, FUNC_KIND);
1049  sprintf(elem->name, "operator%s", $3);
1050  free($3);
1051  print_se(elem);
1052  $$ = elem;
1053}
1054	| OPERATOR type_name '(' ')'
1055{
1056  /* ret_type, name, args, kind */
1057  syntaxelem_t *elem = new_elem(strdup(""), (char *)malloc(strlen($2) + 10),
1058			      NULL, FUNC_KIND);
1059  sprintf(elem->name, "operator %s", $2);
1060  free($2);
1061  print_se(elem);
1062  $$ = elem;
1063}
1064	;
1065
1066const_opt
1067	: /* nothing */				{ $$ = 0; }
1068	| CONST					{ $$ = 1; }
1069	;
1070
1071throw_decl
1072	: /* nothing */				{ $$ = NULL; }
1073	| THROW '(' throw_list ')'
1074{
1075  char *tmp_str = (char *) malloc(strlen($3) + 8);
1076  sprintf(tmp_str, "throw(%s)", $3);
1077  free($3);
1078  $$ = tmp_str;
1079}
1080	;
1081
1082throw_list
1083	: type_name
1084	| throw_list ',' type_name
1085{
1086  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
1087  sprintf(tmp_str, "%s, %s", $1, $3);
1088  free($1);
1089  free($3);
1090  $$ = tmp_str;
1091}
1092	;
1093
1094destructor
1095	: '~' IDENTIFIER '(' ')'
1096{
1097  /* ret_type, name, args, kind */
1098  syntaxelem_t *elem = new_elem(strdup(""), (char *) malloc(strlen($2) + 2),
1099			      NULL, FUNC_KIND);
1100  sprintf(elem->name,"~%s", $2);
1101  free($2);
1102/*   print_se(elem); */
1103  $$ = elem;
1104}
1105	;
1106
1107destructor_skeleton
1108	: scoped_identifier CLCL '~' IDENTIFIER '(' ')'
1109{
1110  /* ret_type, name, args, kind */
1111  syntaxelem_t *elem = new_elem(strdup(""),
1112			      (char *) malloc(strlen($1) + strlen($4) + 4),
1113			      NULL, FUNC_KIND);
1114  sprintf(elem->name,"%s::~%s", $1, $4);
1115  free($1);
1116  free($4);
1117/*   print_se(elem); */
1118  $$ = elem;
1119}
1120	| IDENTIFIER CLCL '~' IDENTIFIER '(' ')'
1121{
1122  /* ret_type, name, args, kind */
1123  syntaxelem_t *elem = new_elem(strdup(""),
1124			      (char *) malloc(strlen($1) + strlen($4) + 4),
1125			      NULL, FUNC_KIND);
1126  sprintf(elem->name,"%s::~%s", $1, $4);
1127  free($1);
1128  free($4);
1129/*   print_se(elem); */
1130  $$ = elem;
1131}
1132	| IDENTIFIER '<' template_instance_arg_list '>' CLCL '~' IDENTIFIER '(' ')'
1133{
1134  /* ret_type, name, args, kind */
1135  syntaxelem_t *elem = new_elem(strdup(""),
1136			      (char *) malloc(strlen($1) + strlen($3) + strlen($7) + 6),
1137			      NULL, FUNC_KIND);
1138  sprintf(elem->name,"%s<%s>::~%s", $1, $3, $7);
1139  free($1);
1140  free($3);
1141  free($7);
1142  $$ = elem;
1143}
1144	| scoped_identifier '<' template_instance_arg_list '>' CLCL '~' IDENTIFIER '(' ')'
1145{
1146  /* ret_type, name, args, kind */
1147  syntaxelem_t *elem = new_elem(strdup(""),
1148			      (char *) malloc(strlen($1) + strlen($3) + strlen($7) + 6),
1149			      NULL, FUNC_KIND);
1150  sprintf(elem->name,"%s<%s>::~%s", $1, $3, $7);
1151  free($1);
1152  free($3);
1153  free($7);
1154  $$ = elem;
1155}
1156	;
1157
1158constructor
1159	: IDENTIFIER '(' parameter_list_opt ')' throw_decl
1160{
1161  /* ret_type, name, args, kind */
1162  syntaxelem_t *elem = new_elem(strdup(""), $1, $3, FUNC_KIND);
1163  elem->throw_decl = $5;
1164/*   print_se(elem); */
1165  $$ = elem;
1166}
1167	;
1168
1169constructor_skeleton
1170	: scoped_identifier '(' parameter_list_opt ')' throw_decl
1171{
1172  /* ret_type, name, args, kind */
1173  syntaxelem_t *elem = new_elem(strdup(""), $1, $3, FUNC_KIND);
1174  elem->throw_decl = $5;
1175/*  print_se(elem); */
1176  $$ = elem;
1177}
1178	| IDENTIFIER '<' template_instance_arg_list '>' CLCL IDENTIFIER '(' parameter_list_opt ')' throw_decl
1179{
1180  /* ret_type, name, args, kind */
1181  syntaxelem_t *elem = new_elem(strdup(""),
1182			      (char *) malloc(strlen($1) + strlen($3) + strlen($6) + 5),
1183			      $8, FUNC_KIND);
1184  sprintf(elem->name,"%s<%s>::%s", $1, $3, $6);
1185  free($1);
1186  free($3);
1187  free($6);
1188  elem->throw_decl = $10;
1189  $$ = elem;
1190}
1191	| scoped_identifier '<' template_instance_arg_list '>' CLCL IDENTIFIER '(' parameter_list_opt ')' throw_decl
1192{
1193  /* ret_type, name, args, kind */
1194  syntaxelem_t *elem = new_elem(strdup(""),
1195			      (char *) malloc(strlen($1) + strlen($3) + strlen($6) + 5),
1196			      $8, FUNC_KIND);
1197  sprintf(elem->name,"%s<%s>::%s", $1, $3, $6);
1198  free($1);
1199  free($3);
1200  free($6);
1201  elem->throw_decl = $10;
1202  $$ = elem;
1203}
1204	;
1205
1206compound_statement
1207	: '{' { if (collectInlineDef() != 0) YYERROR; } '}'
1208	;
1209
1210enum_specifier
1211	: ENUM '{' enumerator_list '}'
1212{
1213  char *tmp_str = (char *) malloc(strlen($3) + 10);
1214  sprintf(tmp_str, "enum { %s }", $3);
1215  free($3);
1216  $$ = tmp_str;
1217}
1218	| ENUM IDENTIFIER '{' enumerator_list '}'
1219{
1220  char *tmp_str = (char *) malloc(strlen($2) + strlen($4) + 11);
1221  sprintf(tmp_str, "enum %s { %s }", $2, $4);
1222  free($2);
1223  free($4);
1224  $$ = tmp_str;
1225}
1226	| ENUM IDENTIFIER
1227{
1228  char *tmp_str = (char *) malloc(strlen($2) + 6);
1229  sprintf(tmp_str, "enum %s", $2);
1230  free($2);
1231  $$ = tmp_str;
1232}
1233	;
1234
1235enumerator_list
1236	: enumerator
1237	| enumerator_list ',' enumerator
1238{
1239  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
1240  sprintf(tmp_str, "%s, %s", $1, $3);
1241  free($1);
1242  free($3);
1243  $$ = tmp_str;
1244}
1245	;
1246
1247enumerator
1248	: IDENTIFIER
1249	| IDENTIFIER '=' constant_value
1250{
1251  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 2);
1252  sprintf(tmp_str, "%s=%s", $1, $3);
1253  free($1);
1254  free($3);
1255  $$ = tmp_str;
1256}
1257	;
1258
1259access_specifier_opt
1260	: /* nothing */
1261	| access_specifier
1262	;
1263
1264access_specifier_list
1265	: access_specifier ':'
1266	| access_specifier_list access_specifier ':'
1267	;
1268
1269access_specifier
1270	: PUBLIC
1271	| PRIVATE
1272	| PROTECTED
1273	;
1274
1275unary_operator
1276	: '&'					{ $$ = strdup("&"); }
1277	| '*'					{ $$ = strdup("*"); }
1278	| '+'					{ $$ = strdup("+"); }
1279	| '-'					{ $$ = strdup("-"); }
1280	| '~'					{ $$ = strdup("~"); }
1281	| '!' 					{ $$ = strdup("!"); }
1282	;
1283
1284binary_operator
1285	: '/'					{ $$ = strdup("/"); }
1286	| '%'					{ $$ = strdup("%"); }
1287	| '^'					{ $$ = strdup("^"); }
1288	| '|'					{ $$ = strdup("|"); }
1289	| '<'					{ $$ = strdup("<"); }
1290	| '>'					{ $$ = strdup(">"); }
1291	| ','					{ $$ = strdup(","); }
1292	;
1293
1294assignment_operator
1295	: '='					{ $$ = strdup("="); }
1296	| MUL_ASSIGN				{ $$ = strdup("*="); }
1297	| DIV_ASSIGN				{ $$ = strdup("/="); }
1298	| MOD_ASSIGN				{ $$ = strdup("%="); }
1299	| ADD_ASSIGN				{ $$ = strdup("+="); }
1300	| SUB_ASSIGN				{ $$ = strdup("-="); }
1301	| LEFT_ASSIGN				{ $$ = strdup("<<="); }
1302	| RIGHT_ASSIGN				{ $$ = strdup(">>="); }
1303	| AND_ASSIGN				{ $$ = strdup("&="); }
1304	| XOR_ASSIGN				{ $$ = strdup("^="); }
1305	| OR_ASSIGN				{ $$ = strdup("|="); }
1306	;
1307
1308any_operator
1309	: assignment_operator
1310	| unary_operator
1311	| binary_operator
1312	| NEW					{ $$ = strdup(" new"); }
1313	| DELETE				{ $$ = strdup(" delete"); }
1314	| PTR_OP				{ $$ = strdup("->"); }
1315	| MEM_PTR_OP				{ $$ = strdup("->*"); }
1316	| INC_OP				{ $$ = strdup("++"); }
1317	| DEC_OP				{ $$ = strdup("--"); }
1318	| LEFT_OP				{ $$ = strdup("<<"); }
1319	| RIGHT_OP				{ $$ = strdup(">>"); }
1320	| LE_OP					{ $$ = strdup("<="); }
1321	| GE_OP					{ $$ = strdup(">="); }
1322	| EQ_OP					{ $$ = strdup("=="); }
1323	| NE_OP					{ $$ = strdup("!="); }
1324	| AND_OP				{ $$ = strdup("&&"); }
1325	| OR_OP					{ $$ = strdup("||"); }
1326	| '[' ']'				{ $$ = strdup("[]"); }
1327	| '(' ')'				{ $$ = strdup("()"); }
1328	;
1329
1330constant_value
1331	: expression
1332	| compound_statement			{ $$ = strdup("{ ... }"); }
1333	;
1334
1335expression
1336	: additive_expression
1337	;
1338
1339primary_expression
1340	: CONSTANT
1341	| '-' CONSTANT
1342{
1343  char *tmp_str = (char *) malloc(strlen($2) + 2);
1344  sprintf(tmp_str, "-%s", $2);
1345  free($2);
1346  $$ = tmp_str;
1347}
1348	| STRING_LITERAL
1349	| IDENTIFIER
1350	| scoped_identifier
1351	| '(' expression ')'
1352{
1353  char *tmp_str = (char *) malloc(strlen($2) + 3);
1354  sprintf(tmp_str, "(%s)", $2);
1355  free($2);
1356  $$ = tmp_str;
1357}
1358	;
1359
1360multiplicative_expression
1361	: primary_expression
1362	| multiplicative_expression '*' primary_expression
1363{
1364  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4);
1365  sprintf(tmp_str, "%s * %s", $1, $3);
1366  free($1);
1367  free($3);
1368  $$ = tmp_str;
1369}
1370	| multiplicative_expression '/' primary_expression
1371{
1372  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4);
1373  sprintf(tmp_str, "%s / %s", $1, $3);
1374  free($1);
1375  free($3);
1376  $$ = tmp_str;
1377}
1378	| multiplicative_expression '%' primary_expression
1379{
1380  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4);
1381  sprintf(tmp_str, "%s %% %s", $1, $3);
1382  free($1);
1383  free($3);
1384  $$ = tmp_str;
1385}
1386	;
1387
1388additive_expression
1389	: multiplicative_expression
1390	| additive_expression '+' multiplicative_expression
1391{
1392  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4);
1393  sprintf(tmp_str, "%s + %s", $1, $3);
1394  free($1);
1395  free($3);
1396  $$ = tmp_str;
1397}
1398	| additive_expression '-' multiplicative_expression
1399{
1400  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4);
1401  sprintf(tmp_str, "%s - %s", $1, $3);
1402  free($1);
1403  free($3);
1404  $$ = tmp_str;
1405}
1406	;
1407
1408
1409union_specifier
1410	: UNION IDENTIFIER '{' variable_specifier_list '}'
1411{
1412  char *tmp_str = (char *) malloc(strlen($2) + strlen($4) + 12);
1413  sprintf(tmp_str, "union %s { %s }", $2, $4);
1414  free($2);
1415  free($4);
1416  $$ = tmp_str;
1417}
1418	| UNION '{' variable_specifier_list '}'
1419{
1420  char *tmp_str = (char *) malloc(strlen($3) + 11);
1421  sprintf(tmp_str, "union { %s }", $3);
1422  free($3);
1423  $$ = tmp_str;
1424}
1425	| UNION IDENTIFIER
1426{
1427  char *tmp_str = (char *) malloc(strlen($2) + 7);
1428  sprintf(tmp_str, "union %s", $2);
1429  free($2);
1430  $$ = tmp_str;
1431}
1432	;
1433
1434class_specifier
1435	: CLASS IDENTIFIER '{' member_list_opt '}'
1436{
1437  syntaxelem_t *child;
1438  /* ret_type, name, args, kind */
1439  syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, CLASS_KIND);
1440  tmp_elem->children = reverse_list($4);
1441
1442  for (child = tmp_elem->children; child != NULL; child = child->next)
1443      child->parent = tmp_elem;
1444
1445/*   print_se(tmp_elem); */
1446  $$ = tmp_elem;
1447}
1448	| CLASS IDENTIFIER ':' superclass_list '{' member_list_opt '}'
1449{
1450  syntaxelem_t *child;
1451  /* ret_type, name, args, kind */
1452  syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, CLASS_KIND);
1453  tmp_elem->children = reverse_list($6);
1454
1455  for (child = tmp_elem->children; child != NULL; child = child->next)
1456      child->parent = tmp_elem;
1457
1458/*   print_se(tmp_elem); */
1459  $$ = tmp_elem;
1460}
1461	| template_specifier CLASS IDENTIFIER '{' member_list_opt '}'
1462{
1463  syntaxelem_t *child;
1464  /* ret_type, name, args, kind */
1465  syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, CLASS_KIND);
1466  tmp_elem->children = reverse_list($5);
1467  tmp_elem->templ = $1;
1468
1469  for (child = tmp_elem->children; child != NULL; child = child->next)
1470      child->parent = tmp_elem;
1471
1472/*   print_se(tmp_elem); */
1473  $$ = tmp_elem;
1474}
1475	| template_specifier CLASS IDENTIFIER ':' superclass_list '{' member_list_opt '}'
1476{
1477  syntaxelem_t *child;
1478  /* ret_type, name, args, kind */
1479  syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, CLASS_KIND);
1480  tmp_elem->children = reverse_list($7);
1481  tmp_elem->templ = $1;
1482
1483  for (child = tmp_elem->children; child != NULL; child = child->next)
1484      child->parent = tmp_elem;
1485
1486/*   print_se(tmp_elem); */
1487  $$ = tmp_elem;
1488}
1489	| STRUCT '{' member_list_opt '}'
1490{
1491  syntaxelem_t *child;
1492  /* ret_type, name, args, kind */
1493  syntaxelem_t *tmp_elem = new_elem(strdup(""), "unnamed_struct",
1494				    NULL, IGNORE_KIND);
1495  tmp_elem->children = reverse_list($3);
1496
1497  for (child = tmp_elem->children; child != NULL; child = child->next)
1498      child->parent = tmp_elem;
1499
1500/*   print_se(tmp_elem); */
1501  $$ = tmp_elem;
1502}
1503	| STRUCT IDENTIFIER '{' member_list_opt '}'
1504{
1505  syntaxelem_t *child;
1506  /* ret_type, name, args, kind */
1507  syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, STRUCT_KIND);
1508  tmp_elem->children = reverse_list($4);
1509
1510  for (child = tmp_elem->children; child != NULL; child = child->next)
1511      child->parent = tmp_elem;
1512
1513/*   print_se(tmp_elem); */
1514  $$ = tmp_elem;
1515}
1516	| STRUCT IDENTIFIER ':' superclass_list '{' member_list_opt '}'
1517{
1518  syntaxelem_t *child;
1519  /* ret_type, name, args, kind */
1520  syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, STRUCT_KIND);
1521  tmp_elem->children = reverse_list($6);
1522
1523  for (child = tmp_elem->children; child != NULL; child = child->next)
1524      child->parent = tmp_elem;
1525
1526/*   print_se(tmp_elem); */
1527  $$ = tmp_elem;
1528}
1529	| template_specifier STRUCT IDENTIFIER '{' member_list_opt '}'
1530{
1531  syntaxelem_t *child;
1532  /* ret_type, name, args, kind */
1533  syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, STRUCT_KIND);
1534  tmp_elem->children = reverse_list($5);
1535  tmp_elem->templ = $1;
1536
1537  for (child = tmp_elem->children; child != NULL; child = child->next)
1538      child->parent = tmp_elem;
1539
1540/*   print_se(tmp_elem); */
1541  $$ = tmp_elem;
1542}
1543	| template_specifier STRUCT IDENTIFIER ':' superclass_list '{' member_list_opt '}'
1544{
1545  syntaxelem_t *child;
1546  /* ret_type, name, args, kind */
1547  syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, STRUCT_KIND);
1548  tmp_elem->children = reverse_list($7);
1549  tmp_elem->templ = $1;
1550
1551  for (child = tmp_elem->children; child != NULL; child = child->next)
1552      child->parent = tmp_elem;
1553
1554/*   print_se(tmp_elem); */
1555  $$ = tmp_elem;
1556}
1557	;
1558
1559superclass_list
1560	: superclass
1561	| superclass_list ',' superclass
1562	;
1563
1564superclass
1565	: access_specifier_opt type_name	{ free($2); }
1566	;
1567
1568friend_specifier
1569	: FRIEND member_func_specifier		{ $2->kind = IGNORE_KIND; }
1570	| FRIEND forward_decl
1571	;
1572
1573member_list_opt
1574	: /* nothing  */ { $$ = NULL; }
1575	| member_list
1576	;
1577
1578member_list
1579	: member_with_access
1580{
1581  if ($1 != NULL)
1582    $1->next = NULL;
1583
1584  $$ = $1;
1585}
1586	| member_list member_with_access
1587{
1588  if ($2 != NULL) {
1589    $2->next = $1;
1590    $$ = $2;
1591  } else {
1592    $$ = $1;
1593  }
1594}
1595	;
1596
1597member_or_error
1598	: member
1599	| error
1600{
1601  log_printf("member_with_access : error.  Attempting to recover...\n");
1602  yyerrok;
1603  yyclearin;
1604  if (error_recovery() != 0) {
1605      log_printf("ERROR recovery could not complete -- YYABORT.\n");
1606      YYABORT;
1607  }
1608  log_printf("ERROR recovery complete.\n");
1609  $$ = NULL;
1610}
1611	;
1612
1613member_with_access
1614	: member_or_error
1615	| access_specifier_list member_or_error	{ $$ = $2; }
1616	;
1617
1618member
1619	: member_specifier ';'
1620	| friend_specifier ';'		{ $$ = NULL; }
1621	| member_func_inlined		{ $1->kind = INLINED_KIND; $$ = $1; }
1622	| ';'				{ $$ = NULL; }
1623	;
1624
1625member_specifier
1626	: multiple_variable_specifier
1627{
1628  /* ret_type, name, args, kind */
1629  syntaxelem_t *elem = new_elem(strdup(""), $1, NULL, IGNORE_KIND);
1630/*   print_se(elem); */
1631  $$ = elem;
1632}
1633	| member_func_specifier
1634	| EXTERN member_func_specifier 		{ $$ = $2; }
1635	| member_func_specifier '=' CONSTANT	{ $1->kind = IGNORE_KIND; free($3); $$ = $1; }
1636	| mem_type_specifier
1637	;
1638
1639mem_type_specifier
1640	: type_specifier
1641	| type_specifier IDENTIFIER		{ free($2); $$ = $1; }
1642	| mem_type_specifier '[' ']'
1643	| mem_type_specifier '[' constant_value ']'
1644{
1645  free($3);
1646  $$ = $1;
1647}
1648	;
1649
1650template_arg
1651	: CLASS IDENTIFIER
1652{
1653  char *tmp_str = (char *) malloc(strlen($2) + 7);
1654  sprintf(tmp_str, "class %s", $2);
1655  free($2);
1656  $$ = tmp_str;
1657}
1658	| type_name IDENTIFIER
1659{
1660  char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2);
1661  sprintf(tmp_str, "%s %s", $1, $2);
1662  free($1);
1663  free($2);
1664  $$ = tmp_str;
1665}
1666	;
1667
1668template_arg_list
1669	: template_arg
1670	| template_arg_list ',' template_arg
1671{
1672  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
1673  sprintf(tmp_str, "%s, %s", $1, $3);
1674  free($1);
1675  free($3);
1676  $$ = tmp_str;
1677}
1678	;
1679
1680template_instance_arg
1681	: CONSTANT
1682	| type_name
1683	;
1684
1685template_instance_arg_list
1686	: template_instance_arg
1687	| template_instance_arg_list ',' template_instance_arg
1688{
1689  char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
1690  sprintf(tmp_str, "%s, %s", $1, $3);
1691  free($1);
1692  free($3);
1693  $$ = tmp_str;
1694}
1695	;
1696
1697template_specifier
1698	: TEMPLATE '<' template_arg_list '>'
1699{
1700  char *tmp_str = (char *) malloc(strlen($3) + 12);
1701  sprintf(tmp_str, "template <%s>", $3);
1702  free($3);
1703  $$ = tmp_str;
1704}
1705	;
1706
1707%%
1708
1709static int yyerror(char *s /*UNUSED*/)
1710{
1711  if (outfile != NULL)
1712    fflush(outfile);
1713
1714  return 0;
1715}
1716
1717static int error_recovery()
1718{
1719  extern char linebuf[];
1720  extern int lineno;
1721  extern int column;
1722  extern int tokens_seen;
1723
1724#ifdef SGDEBUG
1725  log_printf("parse error at line %d, file %s:\n%s\n%*s\n",
1726	     lineno, currentFile, linebuf, column, "^");
1727  log_flush();
1728#endif /* SGDEBUG */
1729
1730  if (tokens_seen == 0) {
1731    /*
1732     * if we've seen no tokens but we're in an error, we must have
1733     * hit an EOF, either by stdin, or on a file.  Just give up
1734     * now instead of complaining.
1735     */
1736    return -1;
1737
1738  } else {
1739    fprintf(stderr, "parse error at line %d, file %s:\n%s\n%*s\n",
1740	    lineno, currentFile, linebuf, column, "^");
1741  }
1742
1743  linebuf[0] = '\0';
1744
1745  for (;;) {
1746    int result = yylex();
1747
1748    if (result <= 0) {
1749      /* fatal error: Unexpected EOF during parse error recovery */
1750
1751#ifdef SGDEBUG
1752      log_printf("EOF in error recovery, line %d, file %s\n",
1753		 lineno, currentFile);
1754      log_flush();
1755#endif /* SGDEBUG */
1756
1757      fprintf(stderr, "EOF in error recovery, line %d, file %s\n",
1758	      lineno, currentFile);
1759
1760      return -1;
1761    }
1762
1763    switch(result) {
1764    case IDENTIFIER:
1765    case CONSTANT:
1766    case STRING_LITERAL:
1767    case CHAR:
1768    case SHORT:
1769    case INT:
1770    case LONG:
1771    case SIGNED:
1772    case UNSIGNED:
1773    case FLOAT:
1774    case DOUBLE:
1775    case VOID:
1776      free(yylval.string);
1777      break;
1778    case (int) '{':
1779      if (collectInlineDef() != 0)
1780	return -1;
1781      result = yylex();
1782      return 0;
1783    case (int) ';':
1784      return 0;
1785    }
1786  }
1787}
1788