1785 lines
44 KiB
Plaintext
1785 lines
44 KiB
Plaintext
%{
|
|
/*
|
|
* FILE: parser.y
|
|
* AUTH: Michael John Radwin <mjr@acm.org>
|
|
*
|
|
* DESC: stubgen grammar description. Portions borrowed from
|
|
* Newcastle University's Arjuna project (http://arjuna.ncl.ac.uk/),
|
|
* and Jeff Lee's ANSI Grammar
|
|
* (ftp://ftp.uu.net/usenet/net.sources/ansi.c.grammar.Z)
|
|
* This grammar is only a subset of the real C++ language.
|
|
*
|
|
* DATE: Thu Aug 15 13:10:06 EDT 1996
|
|
* $Id: parser.y,v 1.1 2003-09-21 22:46:55 ocoursiere Exp $
|
|
*
|
|
* Copyright (c) 1996-1998 Michael John Radwin
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* --------------------------------------------------------------------
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
* Revision 1.1 2001/11/07 10:06:07 ithamar
|
|
* Added stubgen to CVS
|
|
*
|
|
* Revision 1.72 1998/07/07 00:14:06 mradwin
|
|
* removed extra space from throw_decl, cleaned up memory leak
|
|
* in ctor skeleton
|
|
*
|
|
* Revision 1.71 1998/06/11 14:52:09 mradwin
|
|
* allow for empty class declarations, such as
|
|
* class Element {};
|
|
* also, differentiate structs from classes with
|
|
* new STRUCT_KIND tag.
|
|
* New version: 2.04
|
|
*
|
|
* Revision 1.70 1998/05/11 19:49:11 mradwin
|
|
* Version 2.03 (updated copyright information).
|
|
*
|
|
* Revision 1.69 1998/04/07 23:43:34 mradwin
|
|
* changed error-handling code significantly.
|
|
* several functions now return a value, and instead of
|
|
* calling fatal(), we do a YYABORT or YYERROR to get out
|
|
* of the parsing state.
|
|
* New version: 2.02.
|
|
*
|
|
* Revision 1.68 1998/03/28 02:59:41 mradwin
|
|
* working on slightly better error recovery; not done yet.
|
|
*
|
|
* Revision 1.67 1998/03/28 02:34:56 mradwin
|
|
* added multi-line function parameters
|
|
* also changed pointer and reference (* and &) types so there
|
|
* is no trailing space before the parameter name.
|
|
*
|
|
* Revision 1.66 1998/01/12 19:39:11 mradwin
|
|
* modified rcsid
|
|
*
|
|
* Revision 1.65 1997/11/13 22:50:55 mradwin
|
|
* moved copyright from parser.y to main.c
|
|
*
|
|
* Revision 1.64 1997/11/13 22:40:15 mradwin
|
|
* fixed a silly comment bug
|
|
*
|
|
* Revision 1.63 1997/11/13 22:37:31 mradwin
|
|
* changed char[] to char * to make non-gcc compilers
|
|
* a little happier. We need to #define const to nothing
|
|
* for other compilers as well.
|
|
*
|
|
* Revision 1.62 97/11/13 21:29:30 21:29:30 mradwin (Michael Radwin)
|
|
* moved code from parser.y to main.c
|
|
*
|
|
* Revision 1.61 1997/11/13 21:10:17 mradwin
|
|
* renamed stubgen.[ly] to parser.y lexer.l
|
|
*
|
|
* Revision 1.60 1997/11/11 04:11:29 mradwin
|
|
* fixed command-line flags: invalid options now force usgage.
|
|
*
|
|
* Revision 1.59 1997/11/11 04:03:56 mradwin
|
|
* changed version info
|
|
*
|
|
* Revision 1.58 1997/11/11 03:54:05 mradwin
|
|
* fixed a long-standing bug with -b option. a typo was causing
|
|
* the -b flag to be ignored.
|
|
*
|
|
* Revision 1.57 1997/11/11 03:52:06 mradwin
|
|
* changed fatal()
|
|
*
|
|
* Revision 1.56 1997/11/05 03:02:02 mradwin
|
|
* Modified logging routines.
|
|
*
|
|
* Revision 1.55 1997/11/05 02:14:38 mradwin
|
|
* Made some compiler warnings disappear.
|
|
*
|
|
* Revision 1.54 1997/11/01 23:26:13 mradwin
|
|
* new Revision string and usage info
|
|
*
|
|
* Revision 1.53 1997/11/01 23:12:43 mradwin
|
|
* greatly improved error-recovery. errors no longer spill over
|
|
* into other files because the yyerror state is properly reset.
|
|
*
|
|
* Revision 1.52 1997/10/27 01:14:23 mradwin
|
|
* fixed constant_value so it supports simple arithmetic. it's
|
|
* not as robust as full expressions, but this will handle the
|
|
* char buffer[BUFSIZE + 1] problem.
|
|
*
|
|
* Also removed expansion rules that simply did { $$ = $1; } because
|
|
* that action is implicit anyway.
|
|
*
|
|
* Revision 1.51 1997/10/26 23:16:32 mradwin
|
|
* changed inform_user and fatal functions to use varargs
|
|
*
|
|
* Revision 1.50 1997/10/26 22:27:07 mradwin
|
|
* Fixed this bug:
|
|
* stubgen dies on the following because the protected section is empty:
|
|
*
|
|
* class WidgetCsg : public WidgetLens {
|
|
* protected:
|
|
*
|
|
* public:
|
|
* virtual ~WidgetCsg() {}
|
|
* WidgetCsg();
|
|
* };
|
|
*
|
|
* Error:
|
|
* stubgen version 2.0-beta $Revision: 1.1 $.
|
|
* parse error at line 4, file test.H:
|
|
* public:
|
|
* ^
|
|
*
|
|
* Revision 1.49 1997/10/16 19:42:48 mradwin
|
|
* added support for elipses, static member/array initializers,
|
|
* and bitfields.
|
|
*
|
|
* Revision 1.48 1997/10/16 17:35:39 mradwin
|
|
* cleaned up usage info
|
|
*
|
|
* Revision 1.47 1997/10/16 17:12:59 mradwin
|
|
* handle extern "C" blocks better now, and support multi-line
|
|
* macros. still need error-checking.
|
|
*
|
|
* Revision 1.46 1997/10/15 22:09:06 mradwin
|
|
* changed tons of names. stubelem -> sytaxelem,
|
|
* stubin -> infile, stubout -> outfile, stublog -> logfile.
|
|
*
|
|
* Revision 1.45 1997/10/15 21:33:36 mradwin
|
|
* fixed up function_hdr
|
|
*
|
|
* Revision 1.44 1997/10/15 21:33:02 mradwin
|
|
* *** empty log message ***
|
|
*
|
|
* Revision 1.43 1997/10/15 17:42:37 mradwin
|
|
* added support for 'extern "C" { ... }' blocks.
|
|
*
|
|
* Revision 1.42 1997/09/26 20:59:18 mradwin
|
|
* now allow "struct foobar *f" to appear in a parameter
|
|
* list or as a variable decl. Had to remove the
|
|
* class_or_struct rule and blow up the class_specifier
|
|
* description.
|
|
*
|
|
* Revision 1.41 1997/09/26 19:02:18 mradwin
|
|
* fixed memory leak involving template decls in skeleton code.
|
|
* Leads me to believe that skel_elemcmp() is flawed, because
|
|
* it may rely in parent->templ info.
|
|
*
|
|
* Revision 1.40 1997/09/26 18:44:22 mradwin
|
|
* changed parameter handing from char *'s to an argument type
|
|
* to facilitate comparisons between skeleton code
|
|
* and header code. Now we can correctly recognize different
|
|
* parameter names while still maintaining the same signature.
|
|
*
|
|
* Revision 1.39 1997/09/26 00:47:29 mradwin
|
|
* added better base type support -- recognize things like
|
|
* "long long" and "short int" now.
|
|
*
|
|
* Revision 1.38 1997/09/19 18:16:37 mradwin
|
|
* allowed an instance name to come after a class, struct,
|
|
* union, or enum. This improves parseability of typedefs
|
|
* commonly found in c header files, although true typedefs are
|
|
* not understood.
|
|
*
|
|
* Revision 1.37 1997/09/15 22:38:28 mradwin
|
|
* did more revision on the SGDEBUG stuff
|
|
*
|
|
* Revision 1.36 1997/09/15 19:05:26 mradwin
|
|
* allow logging to be compiled out by turning off SGDEBUG
|
|
*
|
|
* Revision 1.35 1997/09/12 00:58:43 mradwin
|
|
* duh, silly me. messed up compilation.
|
|
*
|
|
* Revision 1.34 1997/09/12 00:57:49 mradwin
|
|
* Revision string inserted in usage
|
|
*
|
|
* Revision 1.33 1997/09/12 00:51:19 mradwin
|
|
* string copyright added to code for binary copyright.
|
|
*
|
|
* Revision 1.32 1997/09/12 00:47:21 mradwin
|
|
* some more compactness of grammar with parameter_list_opt
|
|
* and also ampersand_opt
|
|
*
|
|
* Revision 1.31 1997/09/12 00:26:19 mradwin
|
|
* better template support, but still poor
|
|
*
|
|
* Revision 1.30 1997/09/08 23:24:51 mradwin
|
|
* changes to error-handling code.
|
|
* also got rid of the %type <flag> for the top-level rules
|
|
*
|
|
* Revision 1.30 1997/09/08 23:20:02 mradwin
|
|
* some error reporting changes and default values for top-level
|
|
* grammar stuff.
|
|
*
|
|
* Revision 1.29 1997/09/08 17:54:24 mradwin
|
|
* cleaned up options and usage info.
|
|
*
|
|
* Revision 1.28 1997/09/05 19:38:04 mradwin
|
|
* changed options for .ext instead of -l or -x
|
|
*
|
|
* Revision 1.27 1997/09/05 19:17:06 mradwin
|
|
* works for scanning old versions, except for parameter
|
|
* names that differ between .H and .C files.
|
|
*
|
|
* Revision 1.26 1997/09/05 16:34:36 mradwin
|
|
* GPL-ized code.
|
|
*
|
|
* Revision 1.25 1997/09/05 16:11:44 mradwin
|
|
* some simple cleanup before GPL-izing the code
|
|
*
|
|
* Revision 1.24 1997/09/04 19:50:34 mradwin
|
|
* whoo-hoo! by blowing up the description
|
|
* exponentially, it works!
|
|
*
|
|
* Revision 1.23 1997/03/20 16:05:41 mjr
|
|
* renamed syntaxelem to syntaxelem_t, cleaned up throw_decl
|
|
*
|
|
* Revision 1.22 1996/10/02 15:16:57 mjr
|
|
* using pathname.h instead of libgen.h
|
|
*
|
|
* Revision 1.21 1996/09/12 14:44:49 mjr
|
|
* Added throw decl recognition (great, another 4 bytes in syntaxelem)
|
|
* and cleaned up the grammar so that const_opt appears in far fewer
|
|
* places. const_opt is by default 0 as well, so we don't need to
|
|
* pass it as an arg to new_elem().
|
|
*
|
|
* I also added a fix to a potential bug with the MINIT and INLIN
|
|
* exclusive start states. I think they could have been confused
|
|
* by braces within comments, so now I'm grabbing comments in those
|
|
* states as well.
|
|
*
|
|
* Revision 1.20 1996/09/12 04:55:22 mjr
|
|
* changed expand strategy. Don't expand while parsing now;
|
|
* enqueue as we go along and expand at the end. Eventually
|
|
* we'll need to provide similar behavior for when we parse
|
|
* .C files
|
|
*
|
|
* Revision 1.19 1996/09/12 03:46:10 mjr
|
|
* No concrete changes in code. Just added some sanity by
|
|
* factoring out code into util.[ch] and putting some prototypes
|
|
* that were in table.h into stubgen.y where they belong.
|
|
*
|
|
* Revision 1.18 1996/09/06 14:32:48 mjr
|
|
* defined the some_KIND constants for clarity, and made
|
|
* expandClass return immediately if it was give something other
|
|
* than a CLASS_KIND element.
|
|
*
|
|
* Revision 1.17 1996/09/06 14:05:44 mjr
|
|
* Almost there with expanded operator goodies. Still need
|
|
* to get OPERATOR type_name to work.
|
|
*
|
|
* Revision 1.16 1996/09/04 22:28:09 mjr
|
|
* nested classes work and default arguments are now removed
|
|
* from the parameter lists.
|
|
*
|
|
* Revision 1.15 1996/09/04 20:01:57 mjr
|
|
* non-functional expanded code. needs work.
|
|
*
|
|
* Revision 1.14 1996/09/01 21:29:34 mjr
|
|
* put the expanded_operator code back in as a useless rule.
|
|
* oughta think about fixing it up if possible
|
|
*
|
|
* Revision 1.13 1996/09/01 20:59:48 mjr
|
|
* Added collectMemberInitList() function, which is similar
|
|
* to collectInlineDef() and also the exclusive state MINIT
|
|
*
|
|
* Revision 1.12 1996/08/23 05:09:19 mjr
|
|
* fixed up some more portability things
|
|
*
|
|
* Revision 1.11 1996/08/22 02:43:47 mjr
|
|
* added parse error message (using O'Reilly p. 274)
|
|
*
|
|
* Revision 1.10 1996/08/21 18:33:50 mjr
|
|
* added support for template instantiation in the type_name
|
|
* rule. surprisingly it didn't cause any shift/reduce conflicts.
|
|
*
|
|
* Revision 1.9 1996/08/21 17:40:56 mjr
|
|
* added some cpp directives for porting to WIN32
|
|
*
|
|
* Revision 1.8 1996/08/21 00:00:19 mjr
|
|
* approaching stability and usability. command line arguments
|
|
* are handled now and the fopens and fcloses appear to work.
|
|
*
|
|
* Revision 1.7 1996/08/20 20:44:23 mjr
|
|
* added initial support for optind but it is incomplete.
|
|
*
|
|
* Revision 1.6 1996/08/19 17:14:59 mjr
|
|
* misordered args, fixed bug
|
|
*
|
|
* Revision 1.5 1996/08/19 17:11:41 mjr
|
|
* RCS got confused with the RCS-style header goodies.
|
|
* got it cleaned up now.
|
|
*
|
|
* Revision 1.4 1996/08/19 17:01:33 mjr
|
|
* Removed the expanded code checking and added
|
|
* lots of code that duplicates what stubgen.pl did.
|
|
* still need options pretty badly
|
|
*
|
|
* Revision 1.3 1996/08/17 23:21:10 mjr
|
|
* added the expanded operator code, cleaned up tabs.
|
|
* consider putting all of the expanded code in another
|
|
* grammar - this one is getting cluttered.
|
|
*
|
|
*/
|
|
%}
|
|
|
|
%{
|
|
#include "table.h"
|
|
#include "util.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#ifdef WIN32
|
|
#include <malloc.h> /* defintion of alloca */
|
|
#include "getopt.h" /* use GNU getopt */
|
|
#endif /* WIN32 */
|
|
|
|
#ifndef WIN32
|
|
#include <pwd.h>
|
|
#endif /* WIN32 */
|
|
|
|
/* defined in lexer.l */
|
|
extern int collectInlineDef();
|
|
extern int collectMemberInitList();
|
|
|
|
/* defined here in parser.y */
|
|
static int error_recovery();
|
|
static int yyerror(char *);
|
|
static const char rcsid[] = "$Id: parser.y,v 1.1 2003-09-21 22:46:55 ocoursiere Exp $";
|
|
|
|
/* defined in main.c */
|
|
extern FILE *outfile;
|
|
extern char *currentFile;
|
|
extern int lineno;
|
|
|
|
%}
|
|
|
|
%union {
|
|
char *string;
|
|
syntaxelem_t *elt;
|
|
arg_t *arg;
|
|
int flag;
|
|
}
|
|
|
|
%token <string> IDENTIFIER CONSTANT STRING_LITERAL
|
|
%token <string> CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE VOID
|
|
%token NEW DELETE TEMPLATE THROW
|
|
|
|
%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP
|
|
%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
|
|
%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
|
|
%token XOR_ASSIGN OR_ASSIGN CLCL MEM_PTR_OP
|
|
|
|
%token FRIEND OPERATOR CONST CLASS STRUCT UNION ENUM
|
|
%token PROTECTED PRIVATE PUBLIC EXTERN ELIPSIS
|
|
|
|
%type <string> simple_type_name simple_signed_type non_reference_type
|
|
%type <string> scoped_identifier pointer asterisk
|
|
%type <string> type_name binary_operator
|
|
%type <string> assignment_operator unary_operator any_operator
|
|
%type <string> variable_specifier_list union_specifier
|
|
%type <string> constant_value multiple_variable_specifier
|
|
%type <string> enum_specifier enumerator_list enumerator
|
|
%type <string> template_specifier template_arg template_arg_list
|
|
%type <string> template_instance_arg template_instance_arg_list
|
|
%type <string> throw_decl throw_list variable_name bitfield_savvy_identifier
|
|
%type <string> primary_expression expression
|
|
%type <string> multiplicative_expression additive_expression
|
|
%type <flag> const_opt ampersand_opt
|
|
%type <elt> class_specifier
|
|
%type <elt> member_func_specifier function_specifier constructor
|
|
%type <elt> destructor member_specifier member member_with_access
|
|
%type <elt> mem_type_specifier member_or_error
|
|
%type <elt> member_list member_list_opt
|
|
%type <elt> member_func_inlined type_specifier overloaded_op_specifier
|
|
%type <elt> member_func_skel member_func_skel_spec
|
|
%type <elt> constructor_skeleton destructor_skeleton
|
|
%type <elt> overloaded_op_skeleton function_skeleton
|
|
%type <arg> variable_or_parameter variable_specifier
|
|
%type <arg> parameter_list parameter_list_opt unnamed_parameter
|
|
|
|
|
|
%start translation_unit
|
|
%%
|
|
|
|
translation_unit
|
|
: declaration
|
|
| translation_unit declaration
|
|
;
|
|
|
|
declaration
|
|
: declaration_specifiers ';'
|
|
| EXTERN STRING_LITERAL compound_statement
|
|
{
|
|
log_printf("IGNORING extern \"C\" { ... } block.\n");
|
|
free($2);
|
|
}
|
|
| member_func_inlined
|
|
{
|
|
$1->kind = INLINED_KIND;
|
|
log_printf("\nBEGIN matched dec : m_f_i rule --");
|
|
print_se($1);
|
|
log_printf("END matched dec : m_f_i rule\n");
|
|
}
|
|
| function_skeleton
|
|
{
|
|
$1->kind = SKEL_KIND;
|
|
log_printf("\nBEGIN matched dec : function_skeleton rule --");
|
|
print_se($1);
|
|
enqueue_skeleton($1);
|
|
log_printf("END matched dec : function_skeleton rule\n");
|
|
}
|
|
| ';'
|
|
| error
|
|
{
|
|
log_printf("declaration : error. Attempting to recover...\n");
|
|
yyerrok;
|
|
yyclearin;
|
|
if (error_recovery() != 0) {
|
|
log_printf("ERROR recovery could not complete -- YYABORT.\n");
|
|
YYABORT;
|
|
}
|
|
log_printf("ERROR recovery complete.\n");
|
|
}
|
|
;
|
|
|
|
declaration_specifiers
|
|
: member_specifier
|
|
{
|
|
/* the name of the rule "member_specifier" might be misleading, but
|
|
* this is either a class, struct, union, enum, global var, global
|
|
* prototype, etc.. */
|
|
if ($1->kind == CLASS_KIND || $1->kind == STRUCT_KIND) {
|
|
enqueue_class($1);
|
|
} else {
|
|
log_printf("\nIGNORING dec_spec : mem_spec (%s) --",
|
|
string_kind($1->kind));
|
|
print_se($1);
|
|
log_printf("END IGNORING dec_spec : mem_spec (%s)\n",
|
|
string_kind($1->kind));
|
|
}
|
|
}
|
|
| forward_decl
|
|
;
|
|
|
|
type_specifier
|
|
: union_specifier
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""), $1, NULL, IGNORE_KIND);
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
| enum_specifier
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""), $1, NULL, IGNORE_KIND);
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
| class_specifier
|
|
;
|
|
|
|
ampersand_opt
|
|
: /* nothing */ { $$ = 0; }
|
|
| '&' { $$ = 1; }
|
|
;
|
|
|
|
type_name
|
|
: non_reference_type ampersand_opt
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + ($2 ? 2 : 0) + 1);
|
|
strcpy(tmp_str, $1);
|
|
if ($2)
|
|
strcat(tmp_str, " &");
|
|
free($1);
|
|
$$ = tmp_str;
|
|
}
|
|
| CONST non_reference_type ampersand_opt
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + ($3 ? 2 : 0) + 7);
|
|
sprintf(tmp_str, "const %s%s", $2, ($3 ? " &" : ""));
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
forward_decl
|
|
: CLASS IDENTIFIER { free($2); }
|
|
| CLASS scoped_identifier { free($2); }
|
|
| STRUCT IDENTIFIER { free($2); }
|
|
| STRUCT scoped_identifier { free($2); }
|
|
;
|
|
|
|
non_reference_type
|
|
: scoped_identifier
|
|
| IDENTIFIER
|
|
| STRUCT IDENTIFIER
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + 8);
|
|
strcpy(tmp_str, "struct ");
|
|
strcat(tmp_str, $2);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
| scoped_identifier '<' template_instance_arg_list '>'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
|
|
sprintf(tmp_str, "%s<%s>", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
| IDENTIFIER '<' template_instance_arg_list '>'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
|
|
sprintf(tmp_str, "%s<%s>", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
| scoped_identifier '<' template_instance_arg_list '>' pointer
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + strlen($5) + 4);
|
|
sprintf(tmp_str, "%s<%s> %s", $1, $3, $5);
|
|
free($1);
|
|
free($3);
|
|
free($5);
|
|
$$ = tmp_str;
|
|
}
|
|
| IDENTIFIER '<' template_instance_arg_list '>' pointer
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + strlen($5) + 4);
|
|
sprintf(tmp_str, "%s<%s> %s", $1, $3, $5);
|
|
free($1);
|
|
free($3);
|
|
free($5);
|
|
$$ = tmp_str;
|
|
}
|
|
| scoped_identifier pointer
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2);
|
|
sprintf(tmp_str, "%s %s", $1, $2);
|
|
free($1);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
| IDENTIFIER pointer
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2);
|
|
sprintf(tmp_str, "%s %s", $1, $2);
|
|
free($1);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
| STRUCT IDENTIFIER pointer
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + strlen($3) + 9);
|
|
sprintf(tmp_str, "struct %s %s", $2, $3);
|
|
free($2);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
| simple_signed_type
|
|
| simple_signed_type pointer
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2);
|
|
sprintf(tmp_str, "%s %s", $1, $2);
|
|
free($1);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
simple_signed_type
|
|
: simple_type_name
|
|
| SIGNED simple_type_name
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + 8);
|
|
strcpy(tmp_str,"signed ");
|
|
strcat(tmp_str, $2);
|
|
free($1);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
| UNSIGNED simple_type_name
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + 10);
|
|
strcpy(tmp_str,"unsigned ");
|
|
strcat(tmp_str, $2);
|
|
free($1);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
simple_type_name
|
|
: CHAR
|
|
| SHORT
|
|
| SHORT INT
|
|
{
|
|
$$ = strdup("short int");
|
|
free($1);
|
|
free($2);
|
|
}
|
|
| INT
|
|
| LONG
|
|
| LONG INT
|
|
{
|
|
$$ = strdup("long int");
|
|
free($1);
|
|
free($2);
|
|
}
|
|
| LONG LONG
|
|
{
|
|
$$ = strdup("long long");
|
|
free($1);
|
|
free($2);
|
|
}
|
|
| LONG LONG INT
|
|
{
|
|
$$ = strdup("long long int");
|
|
free($1);
|
|
free($2);
|
|
free($3);
|
|
}
|
|
| UNSIGNED
|
|
| FLOAT
|
|
| DOUBLE
|
|
| VOID
|
|
;
|
|
|
|
scoped_identifier
|
|
: IDENTIFIER CLCL IDENTIFIER
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
|
|
sprintf(tmp_str, "%s::%s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
| scoped_identifier CLCL IDENTIFIER
|
|
{
|
|
/* control-Y programming! */
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
|
|
sprintf(tmp_str, "%s::%s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
pointer
|
|
: asterisk
|
|
| pointer asterisk
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 1);
|
|
strcpy(tmp_str,$1);
|
|
strcat(tmp_str,$2);
|
|
free($1);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
asterisk
|
|
: '*' { $$ = strdup("*"); }
|
|
| '*' CONST { $$ = strdup("*const "); }
|
|
;
|
|
|
|
variable_or_parameter
|
|
: type_name bitfield_savvy_identifier
|
|
{
|
|
arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
|
|
new_arg->type = $1;
|
|
new_arg->name = $2;
|
|
new_arg->array = NULL;
|
|
new_arg->next = NULL;
|
|
$$ = new_arg;
|
|
}
|
|
| type_name scoped_identifier
|
|
{
|
|
arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
|
|
new_arg->type = $1;
|
|
new_arg->name = $2;
|
|
new_arg->array = NULL;
|
|
new_arg->next = NULL;
|
|
$$ = new_arg;
|
|
}
|
|
| variable_or_parameter '[' constant_value ']'
|
|
{
|
|
char *old_array = $1->array;
|
|
int old_len = old_array ? strlen(old_array) : 0;
|
|
$1->array = (char *) malloc(strlen($3) + old_len + 3);
|
|
sprintf($1->array, "%s[%s]", old_array ? old_array : "", $3);
|
|
free($3);
|
|
if (old_array)
|
|
free(old_array);
|
|
$$ = $1;
|
|
}
|
|
| variable_or_parameter '[' ']'
|
|
{
|
|
char *old_array = $1->array;
|
|
int old_len = old_array ? strlen(old_array) : 0;
|
|
$1->array = (char *) malloc(old_len + 3);
|
|
sprintf($1->array, "%s[]", old_array ? old_array : "");
|
|
if (old_array)
|
|
free(old_array);
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
bitfield_savvy_identifier
|
|
: IDENTIFIER
|
|
| IDENTIFIER ':' CONSTANT { free($3); $$ = $1;}
|
|
;
|
|
|
|
variable_name
|
|
: bitfield_savvy_identifier
|
|
| pointer IDENTIFIER
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2);
|
|
sprintf(tmp_str, "%s %s", $1, $2);
|
|
free($1);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
| variable_name '[' constant_value ']'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
|
|
sprintf(tmp_str, "%s[%s]", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
| variable_name '[' ']'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + 3);
|
|
strcpy(tmp_str, $1);
|
|
strcat(tmp_str, "[]");
|
|
free($1);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
variable_specifier
|
|
: variable_or_parameter
|
|
| EXTERN variable_or_parameter { $$ = $2; }
|
|
| variable_or_parameter '=' constant_value
|
|
{
|
|
free($3);
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
multiple_variable_specifier
|
|
: variable_specifier
|
|
{
|
|
$$ = args_to_string($1, 0);
|
|
free_args($1);
|
|
}
|
|
| multiple_variable_specifier ',' variable_name
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
|
|
sprintf(tmp_str, "%s, %s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
variable_specifier_list
|
|
: multiple_variable_specifier ';'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + 2);
|
|
sprintf(tmp_str, "%s;", $1);
|
|
free($1);
|
|
$$ = tmp_str;
|
|
}
|
|
| variable_specifier_list multiple_variable_specifier ';'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 3);
|
|
sprintf(tmp_str, "%s\n%s;", $1, $2);
|
|
free($1);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
parameter_list_opt
|
|
: /* nothing */
|
|
{
|
|
$$ = NULL;
|
|
}
|
|
| parameter_list
|
|
{
|
|
$$ = reverse_arg_list($1);
|
|
}
|
|
| parameter_list ',' ELIPSIS
|
|
{
|
|
arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
|
|
new_arg->type = strdup("...");
|
|
new_arg->name = NULL;
|
|
new_arg->array = NULL;
|
|
new_arg->next = $1;
|
|
$$ = reverse_arg_list(new_arg);
|
|
}
|
|
| ELIPSIS
|
|
{
|
|
arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
|
|
new_arg->type = strdup("...");
|
|
new_arg->name = NULL;
|
|
new_arg->array = NULL;
|
|
new_arg->next = NULL;
|
|
$$ = new_arg;
|
|
}
|
|
;
|
|
|
|
parameter_list
|
|
: variable_specifier
|
|
| unnamed_parameter
|
|
| parameter_list ',' variable_specifier
|
|
{
|
|
$3->next = $1;
|
|
$$ = $3;
|
|
}
|
|
| parameter_list ',' unnamed_parameter
|
|
{
|
|
$3->next = $1;
|
|
$$ = $3;
|
|
}
|
|
;
|
|
|
|
unnamed_parameter
|
|
: type_name
|
|
{
|
|
arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
|
|
new_arg->type = $1;
|
|
new_arg->name = NULL;
|
|
new_arg->array = NULL;
|
|
new_arg->next = NULL;
|
|
$$ = new_arg;
|
|
}
|
|
| type_name '=' constant_value
|
|
{
|
|
arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t));
|
|
new_arg->type = $1;
|
|
new_arg->name = NULL;
|
|
new_arg->array = NULL;
|
|
new_arg->next = NULL;
|
|
free($3);
|
|
$$ = new_arg;
|
|
}
|
|
| unnamed_parameter '[' constant_value ']'
|
|
{
|
|
char *old_array = $1->array;
|
|
int old_len = old_array ? strlen(old_array) : 0;
|
|
$1->array = (char *) malloc(strlen($3) + old_len + 3);
|
|
sprintf($1->array, "%s[%s]", old_array ? old_array : "", $3);
|
|
free($3);
|
|
if (old_array)
|
|
free(old_array);
|
|
$$ = $1;
|
|
}
|
|
| unnamed_parameter '[' ']'
|
|
{
|
|
char *old_array = $1->array;
|
|
int old_len = old_array ? strlen(old_array) : 0;
|
|
$1->array = (char *) malloc(old_len + 3);
|
|
sprintf($1->array, "%s[]", old_array ? old_array : "");
|
|
if (old_array)
|
|
free(old_array);
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
function_skeleton
|
|
: member_func_skel compound_statement
|
|
| constructor_skeleton ':'
|
|
{ if (collectMemberInitList() != 0) YYERROR; } compound_statement
|
|
| template_specifier member_func_skel compound_statement
|
|
{
|
|
/* I think this is the correct behavior, but skel_elemcmp is wrong */
|
|
/* $2->templ = $1; */
|
|
free($1);
|
|
$$ = $2;
|
|
}
|
|
| template_specifier constructor_skeleton ':'
|
|
{ if (collectMemberInitList() != 0) YYERROR; } compound_statement
|
|
{
|
|
/* I think this is the correct behavior, but skel_elemcmp is wrong */
|
|
/* $2->templ = $1; */
|
|
free($1);
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
member_func_inlined
|
|
: member_func_specifier compound_statement
|
|
| constructor ':'
|
|
{ if (collectMemberInitList() != 0) YYERROR; } compound_statement
|
|
;
|
|
|
|
member_func_skel
|
|
: member_func_skel_spec const_opt throw_decl
|
|
{
|
|
$1->const_flag = $2;
|
|
$1->throw_decl = $3;
|
|
$$ = $1;
|
|
}
|
|
| constructor_skeleton
|
|
| destructor_skeleton
|
|
;
|
|
|
|
member_func_specifier
|
|
: function_specifier const_opt throw_decl
|
|
{
|
|
$1->const_flag = $2;
|
|
$1->throw_decl = $3;
|
|
$$ = $1;
|
|
}
|
|
| constructor
|
|
| destructor
|
|
;
|
|
|
|
|
|
member_func_skel_spec
|
|
: type_name scoped_identifier '(' parameter_list_opt ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem($1, $2, $4, FUNC_KIND);
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
| type_name IDENTIFIER '<' template_instance_arg_list '>' CLCL IDENTIFIER '(' parameter_list_opt ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem($1,
|
|
(char *) malloc(strlen($2) + strlen($4) + strlen($7) + 5),
|
|
$9, FUNC_KIND);
|
|
sprintf(elem->name,"%s<%s>::%s", $2, $4, $7);
|
|
free($2);
|
|
free($4);
|
|
free($7);
|
|
$$ = elem;
|
|
}
|
|
| overloaded_op_skeleton
|
|
;
|
|
|
|
|
|
|
|
function_specifier
|
|
: type_name IDENTIFIER '(' parameter_list_opt ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem($1, $2, $4, FUNC_KIND);
|
|
print_se(elem);
|
|
$$ = elem;
|
|
}
|
|
| overloaded_op_specifier
|
|
;
|
|
|
|
overloaded_op_skeleton
|
|
: type_name scoped_identifier CLCL OPERATOR any_operator '(' parameter_list_opt ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem($1, (char *)malloc(strlen($2) + strlen($5) + 12),
|
|
$7, FUNC_KIND);
|
|
sprintf(elem->name, "%s::operator%s", $2, $5);
|
|
free($2);
|
|
free($5);
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
| scoped_identifier CLCL OPERATOR type_name '(' ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""),
|
|
(char *)malloc(strlen($1) + strlen($4) + 13),
|
|
NULL, FUNC_KIND);
|
|
sprintf(elem->name, "%s::operator %s", $1, $4);
|
|
free($1);
|
|
free($4);
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
| type_name IDENTIFIER CLCL OPERATOR any_operator '(' parameter_list_opt ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem($1, (char *)malloc(strlen($2) + strlen($5) + 12),
|
|
$7, FUNC_KIND);
|
|
sprintf(elem->name, "%s::operator%s", $2, $5);
|
|
free($2);
|
|
free($5);
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
| IDENTIFIER CLCL OPERATOR type_name '(' ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""),
|
|
(char *)malloc(strlen($1) + strlen($4) + 13),
|
|
NULL, FUNC_KIND);
|
|
sprintf(elem->name, "%s::operator %s", $1, $4);
|
|
free($1);
|
|
free($4);
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
;
|
|
|
|
overloaded_op_specifier
|
|
: type_name OPERATOR any_operator '(' parameter_list_opt ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem($1, (char *)malloc(strlen($3) + 9),
|
|
$5, FUNC_KIND);
|
|
sprintf(elem->name, "operator%s", $3);
|
|
free($3);
|
|
print_se(elem);
|
|
$$ = elem;
|
|
}
|
|
| OPERATOR type_name '(' ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""), (char *)malloc(strlen($2) + 10),
|
|
NULL, FUNC_KIND);
|
|
sprintf(elem->name, "operator %s", $2);
|
|
free($2);
|
|
print_se(elem);
|
|
$$ = elem;
|
|
}
|
|
;
|
|
|
|
const_opt
|
|
: /* nothing */ { $$ = 0; }
|
|
| CONST { $$ = 1; }
|
|
;
|
|
|
|
throw_decl
|
|
: /* nothing */ { $$ = NULL; }
|
|
| THROW '(' throw_list ')'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($3) + 8);
|
|
sprintf(tmp_str, "throw(%s)", $3);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
throw_list
|
|
: type_name
|
|
| throw_list ',' type_name
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
|
|
sprintf(tmp_str, "%s, %s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
destructor
|
|
: '~' IDENTIFIER '(' ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""), (char *) malloc(strlen($2) + 2),
|
|
NULL, FUNC_KIND);
|
|
sprintf(elem->name,"~%s", $2);
|
|
free($2);
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
;
|
|
|
|
destructor_skeleton
|
|
: scoped_identifier CLCL '~' IDENTIFIER '(' ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""),
|
|
(char *) malloc(strlen($1) + strlen($4) + 4),
|
|
NULL, FUNC_KIND);
|
|
sprintf(elem->name,"%s::~%s", $1, $4);
|
|
free($1);
|
|
free($4);
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
| IDENTIFIER CLCL '~' IDENTIFIER '(' ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""),
|
|
(char *) malloc(strlen($1) + strlen($4) + 4),
|
|
NULL, FUNC_KIND);
|
|
sprintf(elem->name,"%s::~%s", $1, $4);
|
|
free($1);
|
|
free($4);
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
| IDENTIFIER '<' template_instance_arg_list '>' CLCL '~' IDENTIFIER '(' ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""),
|
|
(char *) malloc(strlen($1) + strlen($3) + strlen($7) + 6),
|
|
NULL, FUNC_KIND);
|
|
sprintf(elem->name,"%s<%s>::~%s", $1, $3, $7);
|
|
free($1);
|
|
free($3);
|
|
free($7);
|
|
$$ = elem;
|
|
}
|
|
| scoped_identifier '<' template_instance_arg_list '>' CLCL '~' IDENTIFIER '(' ')'
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""),
|
|
(char *) malloc(strlen($1) + strlen($3) + strlen($7) + 6),
|
|
NULL, FUNC_KIND);
|
|
sprintf(elem->name,"%s<%s>::~%s", $1, $3, $7);
|
|
free($1);
|
|
free($3);
|
|
free($7);
|
|
$$ = elem;
|
|
}
|
|
;
|
|
|
|
constructor
|
|
: IDENTIFIER '(' parameter_list_opt ')' throw_decl
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""), $1, $3, FUNC_KIND);
|
|
elem->throw_decl = $5;
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
;
|
|
|
|
constructor_skeleton
|
|
: scoped_identifier '(' parameter_list_opt ')' throw_decl
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""), $1, $3, FUNC_KIND);
|
|
elem->throw_decl = $5;
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
| IDENTIFIER '<' template_instance_arg_list '>' CLCL IDENTIFIER '(' parameter_list_opt ')' throw_decl
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""),
|
|
(char *) malloc(strlen($1) + strlen($3) + strlen($6) + 5),
|
|
$8, FUNC_KIND);
|
|
sprintf(elem->name,"%s<%s>::%s", $1, $3, $6);
|
|
free($1);
|
|
free($3);
|
|
free($6);
|
|
elem->throw_decl = $10;
|
|
$$ = elem;
|
|
}
|
|
| scoped_identifier '<' template_instance_arg_list '>' CLCL IDENTIFIER '(' parameter_list_opt ')' throw_decl
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""),
|
|
(char *) malloc(strlen($1) + strlen($3) + strlen($6) + 5),
|
|
$8, FUNC_KIND);
|
|
sprintf(elem->name,"%s<%s>::%s", $1, $3, $6);
|
|
free($1);
|
|
free($3);
|
|
free($6);
|
|
elem->throw_decl = $10;
|
|
$$ = elem;
|
|
}
|
|
;
|
|
|
|
compound_statement
|
|
: '{' { if (collectInlineDef() != 0) YYERROR; } '}'
|
|
;
|
|
|
|
enum_specifier
|
|
: ENUM '{' enumerator_list '}'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($3) + 10);
|
|
sprintf(tmp_str, "enum { %s }", $3);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
| ENUM IDENTIFIER '{' enumerator_list '}'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + strlen($4) + 11);
|
|
sprintf(tmp_str, "enum %s { %s }", $2, $4);
|
|
free($2);
|
|
free($4);
|
|
$$ = tmp_str;
|
|
}
|
|
| ENUM IDENTIFIER
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + 6);
|
|
sprintf(tmp_str, "enum %s", $2);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
enumerator_list
|
|
: enumerator
|
|
| enumerator_list ',' enumerator
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
|
|
sprintf(tmp_str, "%s, %s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
enumerator
|
|
: IDENTIFIER
|
|
| IDENTIFIER '=' constant_value
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 2);
|
|
sprintf(tmp_str, "%s=%s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
access_specifier_opt
|
|
: /* nothing */
|
|
| access_specifier
|
|
;
|
|
|
|
access_specifier_list
|
|
: access_specifier ':'
|
|
| access_specifier_list access_specifier ':'
|
|
;
|
|
|
|
access_specifier
|
|
: PUBLIC
|
|
| PRIVATE
|
|
| PROTECTED
|
|
;
|
|
|
|
unary_operator
|
|
: '&' { $$ = strdup("&"); }
|
|
| '*' { $$ = strdup("*"); }
|
|
| '+' { $$ = strdup("+"); }
|
|
| '-' { $$ = strdup("-"); }
|
|
| '~' { $$ = strdup("~"); }
|
|
| '!' { $$ = strdup("!"); }
|
|
;
|
|
|
|
binary_operator
|
|
: '/' { $$ = strdup("/"); }
|
|
| '%' { $$ = strdup("%"); }
|
|
| '^' { $$ = strdup("^"); }
|
|
| '|' { $$ = strdup("|"); }
|
|
| '<' { $$ = strdup("<"); }
|
|
| '>' { $$ = strdup(">"); }
|
|
| ',' { $$ = strdup(","); }
|
|
;
|
|
|
|
assignment_operator
|
|
: '=' { $$ = strdup("="); }
|
|
| MUL_ASSIGN { $$ = strdup("*="); }
|
|
| DIV_ASSIGN { $$ = strdup("/="); }
|
|
| MOD_ASSIGN { $$ = strdup("%="); }
|
|
| ADD_ASSIGN { $$ = strdup("+="); }
|
|
| SUB_ASSIGN { $$ = strdup("-="); }
|
|
| LEFT_ASSIGN { $$ = strdup("<<="); }
|
|
| RIGHT_ASSIGN { $$ = strdup(">>="); }
|
|
| AND_ASSIGN { $$ = strdup("&="); }
|
|
| XOR_ASSIGN { $$ = strdup("^="); }
|
|
| OR_ASSIGN { $$ = strdup("|="); }
|
|
;
|
|
|
|
any_operator
|
|
: assignment_operator
|
|
| unary_operator
|
|
| binary_operator
|
|
| NEW { $$ = strdup(" new"); }
|
|
| DELETE { $$ = strdup(" delete"); }
|
|
| PTR_OP { $$ = strdup("->"); }
|
|
| MEM_PTR_OP { $$ = strdup("->*"); }
|
|
| INC_OP { $$ = strdup("++"); }
|
|
| DEC_OP { $$ = strdup("--"); }
|
|
| LEFT_OP { $$ = strdup("<<"); }
|
|
| RIGHT_OP { $$ = strdup(">>"); }
|
|
| LE_OP { $$ = strdup("<="); }
|
|
| GE_OP { $$ = strdup(">="); }
|
|
| EQ_OP { $$ = strdup("=="); }
|
|
| NE_OP { $$ = strdup("!="); }
|
|
| AND_OP { $$ = strdup("&&"); }
|
|
| OR_OP { $$ = strdup("||"); }
|
|
| '[' ']' { $$ = strdup("[]"); }
|
|
| '(' ')' { $$ = strdup("()"); }
|
|
;
|
|
|
|
constant_value
|
|
: expression
|
|
| compound_statement { $$ = strdup("{ ... }"); }
|
|
;
|
|
|
|
expression
|
|
: additive_expression
|
|
;
|
|
|
|
primary_expression
|
|
: CONSTANT
|
|
| '-' CONSTANT
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + 2);
|
|
sprintf(tmp_str, "-%s", $2);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
| STRING_LITERAL
|
|
| IDENTIFIER
|
|
| scoped_identifier
|
|
| '(' expression ')'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + 3);
|
|
sprintf(tmp_str, "(%s)", $2);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
multiplicative_expression
|
|
: primary_expression
|
|
| multiplicative_expression '*' primary_expression
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4);
|
|
sprintf(tmp_str, "%s * %s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
| multiplicative_expression '/' primary_expression
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4);
|
|
sprintf(tmp_str, "%s / %s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
| multiplicative_expression '%' primary_expression
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4);
|
|
sprintf(tmp_str, "%s %% %s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
additive_expression
|
|
: multiplicative_expression
|
|
| additive_expression '+' multiplicative_expression
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4);
|
|
sprintf(tmp_str, "%s + %s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
| additive_expression '-' multiplicative_expression
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4);
|
|
sprintf(tmp_str, "%s - %s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
|
|
union_specifier
|
|
: UNION IDENTIFIER '{' variable_specifier_list '}'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + strlen($4) + 12);
|
|
sprintf(tmp_str, "union %s { %s }", $2, $4);
|
|
free($2);
|
|
free($4);
|
|
$$ = tmp_str;
|
|
}
|
|
| UNION '{' variable_specifier_list '}'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($3) + 11);
|
|
sprintf(tmp_str, "union { %s }", $3);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
| UNION IDENTIFIER
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + 7);
|
|
sprintf(tmp_str, "union %s", $2);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
class_specifier
|
|
: CLASS IDENTIFIER '{' member_list_opt '}'
|
|
{
|
|
syntaxelem_t *child;
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, CLASS_KIND);
|
|
tmp_elem->children = reverse_list($4);
|
|
|
|
for (child = tmp_elem->children; child != NULL; child = child->next)
|
|
child->parent = tmp_elem;
|
|
|
|
/* print_se(tmp_elem); */
|
|
$$ = tmp_elem;
|
|
}
|
|
| CLASS IDENTIFIER ':' superclass_list '{' member_list_opt '}'
|
|
{
|
|
syntaxelem_t *child;
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, CLASS_KIND);
|
|
tmp_elem->children = reverse_list($6);
|
|
|
|
for (child = tmp_elem->children; child != NULL; child = child->next)
|
|
child->parent = tmp_elem;
|
|
|
|
/* print_se(tmp_elem); */
|
|
$$ = tmp_elem;
|
|
}
|
|
| template_specifier CLASS IDENTIFIER '{' member_list_opt '}'
|
|
{
|
|
syntaxelem_t *child;
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, CLASS_KIND);
|
|
tmp_elem->children = reverse_list($5);
|
|
tmp_elem->templ = $1;
|
|
|
|
for (child = tmp_elem->children; child != NULL; child = child->next)
|
|
child->parent = tmp_elem;
|
|
|
|
/* print_se(tmp_elem); */
|
|
$$ = tmp_elem;
|
|
}
|
|
| template_specifier CLASS IDENTIFIER ':' superclass_list '{' member_list_opt '}'
|
|
{
|
|
syntaxelem_t *child;
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, CLASS_KIND);
|
|
tmp_elem->children = reverse_list($7);
|
|
tmp_elem->templ = $1;
|
|
|
|
for (child = tmp_elem->children; child != NULL; child = child->next)
|
|
child->parent = tmp_elem;
|
|
|
|
/* print_se(tmp_elem); */
|
|
$$ = tmp_elem;
|
|
}
|
|
| STRUCT '{' member_list_opt '}'
|
|
{
|
|
syntaxelem_t *child;
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *tmp_elem = new_elem(strdup(""), "unnamed_struct",
|
|
NULL, IGNORE_KIND);
|
|
tmp_elem->children = reverse_list($3);
|
|
|
|
for (child = tmp_elem->children; child != NULL; child = child->next)
|
|
child->parent = tmp_elem;
|
|
|
|
/* print_se(tmp_elem); */
|
|
$$ = tmp_elem;
|
|
}
|
|
| STRUCT IDENTIFIER '{' member_list_opt '}'
|
|
{
|
|
syntaxelem_t *child;
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, STRUCT_KIND);
|
|
tmp_elem->children = reverse_list($4);
|
|
|
|
for (child = tmp_elem->children; child != NULL; child = child->next)
|
|
child->parent = tmp_elem;
|
|
|
|
/* print_se(tmp_elem); */
|
|
$$ = tmp_elem;
|
|
}
|
|
| STRUCT IDENTIFIER ':' superclass_list '{' member_list_opt '}'
|
|
{
|
|
syntaxelem_t *child;
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, STRUCT_KIND);
|
|
tmp_elem->children = reverse_list($6);
|
|
|
|
for (child = tmp_elem->children; child != NULL; child = child->next)
|
|
child->parent = tmp_elem;
|
|
|
|
/* print_se(tmp_elem); */
|
|
$$ = tmp_elem;
|
|
}
|
|
| template_specifier STRUCT IDENTIFIER '{' member_list_opt '}'
|
|
{
|
|
syntaxelem_t *child;
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, STRUCT_KIND);
|
|
tmp_elem->children = reverse_list($5);
|
|
tmp_elem->templ = $1;
|
|
|
|
for (child = tmp_elem->children; child != NULL; child = child->next)
|
|
child->parent = tmp_elem;
|
|
|
|
/* print_se(tmp_elem); */
|
|
$$ = tmp_elem;
|
|
}
|
|
| template_specifier STRUCT IDENTIFIER ':' superclass_list '{' member_list_opt '}'
|
|
{
|
|
syntaxelem_t *child;
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, STRUCT_KIND);
|
|
tmp_elem->children = reverse_list($7);
|
|
tmp_elem->templ = $1;
|
|
|
|
for (child = tmp_elem->children; child != NULL; child = child->next)
|
|
child->parent = tmp_elem;
|
|
|
|
/* print_se(tmp_elem); */
|
|
$$ = tmp_elem;
|
|
}
|
|
;
|
|
|
|
superclass_list
|
|
: superclass
|
|
| superclass_list ',' superclass
|
|
;
|
|
|
|
superclass
|
|
: access_specifier_opt type_name { free($2); }
|
|
;
|
|
|
|
friend_specifier
|
|
: FRIEND member_func_specifier { $2->kind = IGNORE_KIND; }
|
|
| FRIEND forward_decl
|
|
;
|
|
|
|
member_list_opt
|
|
: /* nothing */ { $$ = NULL; }
|
|
| member_list
|
|
;
|
|
|
|
member_list
|
|
: member_with_access
|
|
{
|
|
if ($1 != NULL)
|
|
$1->next = NULL;
|
|
|
|
$$ = $1;
|
|
}
|
|
| member_list member_with_access
|
|
{
|
|
if ($2 != NULL) {
|
|
$2->next = $1;
|
|
$$ = $2;
|
|
} else {
|
|
$$ = $1;
|
|
}
|
|
}
|
|
;
|
|
|
|
member_or_error
|
|
: member
|
|
| error
|
|
{
|
|
log_printf("member_with_access : error. Attempting to recover...\n");
|
|
yyerrok;
|
|
yyclearin;
|
|
if (error_recovery() != 0) {
|
|
log_printf("ERROR recovery could not complete -- YYABORT.\n");
|
|
YYABORT;
|
|
}
|
|
log_printf("ERROR recovery complete.\n");
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
member_with_access
|
|
: member_or_error
|
|
| access_specifier_list member_or_error { $$ = $2; }
|
|
;
|
|
|
|
member
|
|
: member_specifier ';'
|
|
| friend_specifier ';' { $$ = NULL; }
|
|
| member_func_inlined { $1->kind = INLINED_KIND; $$ = $1; }
|
|
| ';' { $$ = NULL; }
|
|
;
|
|
|
|
member_specifier
|
|
: multiple_variable_specifier
|
|
{
|
|
/* ret_type, name, args, kind */
|
|
syntaxelem_t *elem = new_elem(strdup(""), $1, NULL, IGNORE_KIND);
|
|
/* print_se(elem); */
|
|
$$ = elem;
|
|
}
|
|
| member_func_specifier
|
|
| EXTERN member_func_specifier { $$ = $2; }
|
|
| member_func_specifier '=' CONSTANT { $1->kind = IGNORE_KIND; free($3); $$ = $1; }
|
|
| mem_type_specifier
|
|
;
|
|
|
|
mem_type_specifier
|
|
: type_specifier
|
|
| type_specifier IDENTIFIER { free($2); $$ = $1; }
|
|
| mem_type_specifier '[' ']'
|
|
| mem_type_specifier '[' constant_value ']'
|
|
{
|
|
free($3);
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
template_arg
|
|
: CLASS IDENTIFIER
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($2) + 7);
|
|
sprintf(tmp_str, "class %s", $2);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
| type_name IDENTIFIER
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2);
|
|
sprintf(tmp_str, "%s %s", $1, $2);
|
|
free($1);
|
|
free($2);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
template_arg_list
|
|
: template_arg
|
|
| template_arg_list ',' template_arg
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
|
|
sprintf(tmp_str, "%s, %s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
template_instance_arg
|
|
: CONSTANT
|
|
| type_name
|
|
;
|
|
|
|
template_instance_arg_list
|
|
: template_instance_arg
|
|
| template_instance_arg_list ',' template_instance_arg
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3);
|
|
sprintf(tmp_str, "%s, %s", $1, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
template_specifier
|
|
: TEMPLATE '<' template_arg_list '>'
|
|
{
|
|
char *tmp_str = (char *) malloc(strlen($3) + 12);
|
|
sprintf(tmp_str, "template <%s>", $3);
|
|
free($3);
|
|
$$ = tmp_str;
|
|
}
|
|
;
|
|
|
|
%%
|
|
|
|
static int yyerror(char *s /*UNUSED*/)
|
|
{
|
|
if (outfile != NULL)
|
|
fflush(outfile);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int error_recovery()
|
|
{
|
|
extern char linebuf[];
|
|
extern int lineno;
|
|
extern int column;
|
|
extern int tokens_seen;
|
|
|
|
#ifdef SGDEBUG
|
|
log_printf("parse error at line %d, file %s:\n%s\n%*s\n",
|
|
lineno, currentFile, linebuf, column, "^");
|
|
log_flush();
|
|
#endif /* SGDEBUG */
|
|
|
|
if (tokens_seen == 0) {
|
|
/*
|
|
* if we've seen no tokens but we're in an error, we must have
|
|
* hit an EOF, either by stdin, or on a file. Just give up
|
|
* now instead of complaining.
|
|
*/
|
|
return -1;
|
|
|
|
} else {
|
|
fprintf(stderr, "parse error at line %d, file %s:\n%s\n%*s\n",
|
|
lineno, currentFile, linebuf, column, "^");
|
|
}
|
|
|
|
linebuf[0] = '\0';
|
|
|
|
for (;;) {
|
|
int result = yylex();
|
|
|
|
if (result <= 0) {
|
|
/* fatal error: Unexpected EOF during parse error recovery */
|
|
|
|
#ifdef SGDEBUG
|
|
log_printf("EOF in error recovery, line %d, file %s\n",
|
|
lineno, currentFile);
|
|
log_flush();
|
|
#endif /* SGDEBUG */
|
|
|
|
fprintf(stderr, "EOF in error recovery, line %d, file %s\n",
|
|
lineno, currentFile);
|
|
|
|
return -1;
|
|
}
|
|
|
|
switch(result) {
|
|
case IDENTIFIER:
|
|
case CONSTANT:
|
|
case STRING_LITERAL:
|
|
case CHAR:
|
|
case SHORT:
|
|
case INT:
|
|
case LONG:
|
|
case SIGNED:
|
|
case UNSIGNED:
|
|
case FLOAT:
|
|
case DOUBLE:
|
|
case VOID:
|
|
free(yylval.string);
|
|
break;
|
|
case (int) '{':
|
|
if (collectInlineDef() != 0)
|
|
return -1;
|
|
result = yylex();
|
|
return 0;
|
|
case (int) ';':
|
|
return 0;
|
|
}
|
|
}
|
|
}
|