wxWidgets/wxPython/wxSWIG/SWIG/parser.y
Robin Dunn c90f71dd8c Since I have made several changes to SWIG over the years to accomodate
special cases and other things in wxPython, and since I plan on making
several more, I've decided to put the SWIG sources in wxPython's CVS
instead of relying on maintaining patches.  This effectivly becomes a
fork of an obsolete version of SWIG, :-( but since SWIG 1.3 still
doesn't have some things I rely on in 1.1, not to mention that my
custom patches would all have to be redone, I felt that this is the
easier road to take.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15307 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2002-04-29 19:56:57 +00:00

4158 lines
116 KiB
Plaintext

%{
/*******************************************************************************
* Simplified Wrapper and Interface Generator (SWIG)
*
* Author : David Beazley
*
* Department of Computer Science
* University of Chicago
* 1100 E 58th Street
* Chicago, IL 60637
* beazley@cs.uchicago.edu
*
* Please read the file LICENSE for the copyright and terms by which SWIG
* can be used and distributed.
*******************************************************************************/
/***********************************************************************
* $Header$
*
* parser.y
*
* YACC parser for parsing function declarations.
*
* *** DISCLAIMER ***
*
* This is the most ugly, incredibly henious, and completely unintelligible
* file in SWIG. While it started out simple, it has grown into a
* monster that is almost unmaintainable. A complete parser rewrite is
* currently in progress that should make this file about 1/4 the size
* that it is now. Needless to say, don't modify this file or even look
* at it for that matter!
***********************************************************************/
#define yylex yylex
extern "C" int yylex();
void yyerror (char *s);
extern int line_number;
extern int start_line;
extern void skip_brace(void);
extern void skip_define(void);
extern void skip_decl(void);
extern int skip_cond(int);
extern void skip_to_end(void);
extern void skip_template(void);
extern void scanner_check_typedef(void);
extern void scanner_ignore_typedef(void);
extern void scanner_clear_start(void);
extern void start_inline(char *, int);
extern void format_string(char *);
extern void swig_pragma(char *, char *);
#include "internal.h"
#ifdef NEED_ALLOC
void *alloca(unsigned n) {
return((void *) malloc(n));
}
#else
// This redefinition is apparently needed on a number of machines,
// particularly HPUX
#undef alloca
#define alloca malloc
#endif
// Initialization flags. These indicate whether or not certain
// features have been initialized. These were added to allow
// interface files without the block (required in previous
// versions).
static int module_init = 0; /* Indicates whether the %module name was given */
static int title_init = 0; /* Indicates whether %title directive has been given */
static int doc_init = 0;
static int lang_init = 0; /* Indicates if the language has been initialized */
static int i;
int Error = 0;
static char temp_name[128];
static DataType *temp_typeptr, temp_type;
static char yy_rename[256];
static int Rename_true = 0;
static DataType *Active_type = 0; // Used to support variable lists
static int Active_extern = 0; // Whether or not list is external
static int Active_static = 0;
static DataType *Active_typedef = 0; // Used for typedef lists
static int InArray = 0; // Used when an array declaration is found
static int in_then = 0;
static int in_else = 0;
static int allow = 1; // Used during conditional compilation
static int doc_scope = 0; // Documentation scoping
static String ArrayString; // Array type attached to parameter names
static String ArrayBackup; // Array backup string
static char *DefArg = 0; // Default argument hack
static char *ConstChar = 0; // Used to store raw character constants
static ParmList *tm_parm = 0; // Parameter list used to hold typemap parameters
static Hash name_hash; // Hash table containing renamings
char *objc_construct = "new"; // Objective-C constructor
char *objc_destruct = "free"; // Objective-C destructor
/* Some macros for building constants */
#define E_BINARY(TARGET, SRC1, SRC2, OP) \
TARGET = new char[strlen(SRC1) + strlen(SRC2) +strlen(OP)+1];\
sprintf(TARGET,"%s%s%s",SRC1,OP,SRC2);
/* C++ modes */
#define CPLUS_PUBLIC 1
#define CPLUS_PRIVATE 2
#define CPLUS_PROTECTED 3
int cplus_mode;
// Declarations of some functions for handling C++
extern void cplus_open_class(char *name, char *rname, char *ctype);
extern void cplus_member_func(char *, char *, DataType *, ParmList *, int);
extern void cplus_constructor(char *, char *, ParmList *);
extern void cplus_destructor(char *, char *);
extern void cplus_variable(char *, char *, DataType *);
extern void cplus_static_func(char *, char *, DataType *, ParmList *);
extern void cplus_declare_const(char *, char *, DataType *, char *);
extern void cplus_class_close(char *);
extern void cplus_inherit(int, char **);
extern void cplus_cleanup(void);
extern void cplus_static_var(char *, char *, DataType *);
extern void cplus_register_type(char *);
extern void cplus_register_scope(Hash *);
extern void cplus_inherit_scope(int, char **);
extern void cplus_add_pragma(char *, char *, char *);
extern DocEntry *cplus_set_class(char *);
extern void cplus_unset_class();
extern void cplus_abort();
// ----------------------------------------------------------------------
// static init_language()
//
// Initialize the target language.
// Does nothing if this function has already been called.
// ----------------------------------------------------------------------
static void init_language() {
if (!lang_init) {
lang->initialize();
// Initialize the documentation system
if (!doctitle) {
doctitle = new DocTitle(title,0);
}
if (!doc_init)
doctitle->usage = title;
doc_stack[0] = doctitle;
doc_stack_top = 0;
int oldignore = IgnoreDoc;
IgnoreDoc = 1;
if (ConfigFile) {
include_file(ConfigFile);
}
IgnoreDoc = oldignore;
}
lang_init = 1;
title_init = 1;
}
// ----------------------------------------------------------------------
// int promote(int t1, int t2)
//
// Promote types (for constant expressions)
// ----------------------------------------------------------------------
int promote(int t1, int t2) {
if ((t1 == T_ERROR) || (t2 == T_ERROR)) return T_ERROR;
if ((t1 == T_DOUBLE) || (t2 == T_DOUBLE)) return T_DOUBLE;
if ((t1 == T_FLOAT) || (t2 == T_FLOAT)) return T_FLOAT;
if ((t1 == T_ULONG) || (t2 == T_ULONG)) return T_ULONG;
if ((t1 == T_LONG) || (t2 == T_LONG)) return T_LONG;
if ((t1 == T_UINT) || (t2 == T_UINT)) return T_UINT;
if ((t1 == T_INT) || (t2 == T_INT)) return T_INT;
if ((t1 == T_USHORT) || (t2 == T_USHORT)) return T_SHORT;
if ((t1 == T_SHORT) || (t2 == T_SHORT)) return T_SHORT;
if ((t1 == T_UCHAR) || (t2 == T_UCHAR)) return T_UCHAR;
if (t1 != t2) {
fprintf(stderr,"%s : Line %d. Type mismatch in constant expression\n",
input_file, line_number);
FatalError();
}
return t1;
}
/* Generate the scripting name of an object. Takes %name directive into
account among other things */
static char *make_name(char *name) {
// Check to see if the name is in the hash
char *nn = (char *) name_hash.lookup(name);
if (nn) return nn; // Yep, return it.
if (Rename_true) {
Rename_true = 0;
return yy_rename;
} else {
// Now check to see if the name contains a $
if (strchr(name,'$')) {
static String temp;
temp = "";
temp << name;
temp.replace("$","_S_");
return temp;
} else {
return name;
}
}
}
/* Return the parent of a documentation entry. If wrapping externally, this is 0 */
static DocEntry *doc_parent() {
if (!WrapExtern)
return doc_stack[doc_stack_top];
else
return 0;
}
// ----------------------------------------------------------------------
// create_function(int ext, char *name, DataType *t, ParmList *l)
//
// Creates a function and manages documentation creation. Really
// only used internally to the parser.
// ----------------------------------------------------------------------
void create_function(int ext, char *name, DataType *t, ParmList *l) {
if (Active_static) return; // Static declaration. Ignore
init_language();
if (WrapExtern) return; // External wrapper file. Ignore
char *iname = make_name(name);
// Check if symbol already exists
if (add_symbol(iname, t, (char *) 0)) {
fprintf(stderr,"%s : Line %d. Function %s multiply defined (2nd definition ignored).\n",
input_file, line_number, iname);
} else {
Stat_func++;
if (Verbose) {
fprintf(stderr,"Wrapping function : ");
emit_extern_func(name, t, l, 0, stderr);
}
// If extern, make an extern declaration in the SWIG wrapper file
if (ext)
emit_extern_func(name, t, l, ext, f_header);
else if (ForceExtern) {
emit_extern_func(name, t, l, 1, f_header);
}
// If this function has been declared inline, produce a function
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
lang->create_function(name, iname, t, l);
l->check_defined();
t->check_defined();
}
scanner_clear_start();
}
// -------------------------------------------------------------------
// create_variable(int ext, char *name, DataType *t)
//
// Create a link to a global variable.
// -------------------------------------------------------------------
void create_variable(int ext, char *name, DataType *t) {
if (WrapExtern) return; // External wrapper file. Ignore
int oldstatus = Status;
if (Active_static) return; // If static ignore
init_language();
char *iname = make_name(name);
if (add_symbol(iname, t, (char *) 0)) {
fprintf(stderr,"%s : Line %d. Variable %s multiply defined (2nd definition ignored).\n",
input_file, line_number, iname);
} else {
Stat_var++;
if (Verbose) {
fprintf(stderr,"Wrapping variable : ");
emit_extern_var(name, t, 0, stderr);
}
// If externed, output an external declaration
if (ext)
emit_extern_var(name, t, ext, f_header);
else if (ForceExtern) {
emit_extern_var(name, t, 1, f_header);
}
// If variable datatype is read-only, we'll force it to be readonly
if (t->status & STAT_READONLY) Status = Status | STAT_READONLY;
// Now dump it out
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
lang->link_variable(name, iname, t);
t->check_defined();
Status = oldstatus;
}
scanner_clear_start();
}
// ------------------------------------------------------------------
// create_constant(char *name, DataType *type, char *value)
//
// Creates a new constant.
// -------------------------------------------------------------------
void create_constant(char *name, DataType *type, char *value) {
if (Active_static) return;
if (WrapExtern) return; // External wrapper file. Ignore
init_language();
if (Rename_true) {
fprintf(stderr,"%s : Line %d. %%name directive ignored with #define\n",
input_file, line_number);
Rename_true = 0;
}
if ((type->type == T_CHAR) && (!type->is_pointer))
type->is_pointer++;
if (!value) value = copy_string(name);
sprintf(temp_name,"const:%s", name);
if (add_symbol(temp_name, type, value)) {
fprintf(stderr,"%s : Line %d. Constant %s multiply defined. (2nd definition ignored)\n",
input_file, line_number, name);
} else {
// Update symbols value if already defined.
update_symbol(name, type, value);
if (!WrapExtern) { // Only wrap the constant if not in %extern mode
Stat_const++;
if (Verbose)
fprintf(stderr,"Creating constant %s = %s\n", name, value);
doc_entry = new DocDecl(name,doc_stack[doc_stack_top]);
lang->declare_const(name, name, type, value);
type->check_defined();
}
}
scanner_clear_start();
}
/* Print out array brackets */
void print_array() {
int i;
for (i = 0; i < InArray; i++)
fprintf(stderr,"[]");
}
/* manipulate small stack for managing if-then-else */
static int then_data[100];
static int else_data[100];
static int allow_data[100];
static int te_index = 0;
static int prev_allow = 1;
void if_push() {
then_data[te_index] = in_then;
else_data[te_index] = in_else;
allow_data[te_index] = allow;
prev_allow = allow;
te_index++;
if (te_index >= 100) {
fprintf(stderr,"SWIG. Internal parser error. if-then-else stack overflow.\n");
SWIG_exit(1);
}
}
void if_pop() {
if (te_index > 0) {
te_index--;
in_then = then_data[te_index];
in_else = else_data[te_index];
allow = allow_data[te_index];
if (te_index > 0) {
prev_allow = allow_data[te_index-1];
} else {
prev_allow = 1;
}
}
}
// Structures for handling code fragments built for nested classes
struct Nested {
String code; // Associated code fragment
int line; // line number where it starts
char *name; // Name associated with this nested class
DataType *type; // Datatype associated with the name
Nested *next; // Next code fragment in list
};
// Some internal variables for saving nested class information
static Nested *nested_list = 0;
// Add a function to the nested list
static void add_nested(Nested *n) {
Nested *n1;
if (!nested_list) nested_list = n;
else {
n1 = nested_list;
while (n1->next) n1 = n1->next;
n1->next = n;
}
}
// Dump all of the nested class declarations to the inline processor
// However. We need to do a few name replacements and other munging
// first. This function must be called before closing a class!
static void dump_nested(char *parent) {
Nested *n,*n1;
n = nested_list;
int oldstatus = Status;
Status = STAT_READONLY;
while (n) {
// Token replace the name of the parent class
n->code.replace("$classname",parent);
// Fix up the name of the datatype (for building typedefs and other stuff)
sprintf(n->type->name,"%s_%s",parent,n->name);
// Add the appropriate declaration to the C++ processor
doc_entry = new DocDecl(n->name,doc_stack[doc_stack_top]);
cplus_variable(n->name,(char *) 0, n->type);
// Dump the code to the scanner
if (Verbose)
fprintf(stderr,"Splitting from %s : (line %d) \n%s\n", parent,n->line, n->code.get());
fprintf(f_header,"\n%s\n", n->code.get());
start_inline(n->code.get(),n->line);
n1 = n->next;
delete n;
n = n1;
}
nested_list = 0;
Status = oldstatus;
}
%}
/* The type of each node in the parse tree
must be one of the elements of the union
given below. This is used to derive the
C++ declaration for "yylval" that appears
in parser.tab.h. */
%union {
char *id;
struct Declaration {
char *id;
int is_pointer;
int is_reference;
} decl;
struct InitList {
char **names;
int count;
} ilist;
struct DocList {
char **names;
char **values;
int count;
} dlist;
struct Define {
char *id;
int type;
} dtype;
DataType *type;
Parm *p;
TMParm *tmparm;
ParmList *pl;
int ivalue;
};
%token <id> ID
%token <id> HBLOCK WRAPPER POUND
%token <id> STRING
%token <id> NUM_INT NUM_FLOAT CHARCONST NUM_UNSIGNED NUM_LONG NUM_ULONG
%token <ivalue> TYPEDEF
%token <type> TYPE_INT TYPE_UNSIGNED TYPE_SHORT TYPE_LONG TYPE_FLOAT TYPE_DOUBLE TYPE_CHAR TYPE_VOID TYPE_SIGNED TYPE_BOOL TYPE_TYPEDEF
%token LPAREN RPAREN COMMA SEMI EXTERN INIT LBRACE RBRACE DEFINE PERIOD
%token CONST STRUCT UNION EQUAL SIZEOF MODULE LBRACKET RBRACKET
%token WEXTERN ILLEGAL
%token READONLY READWRITE NAME RENAME INCLUDE CHECKOUT ADDMETHODS PRAGMA
%token CVALUE COUT
%token ENUM ENDDEF MACRO
%token CLASS PRIVATE PUBLIC PROTECTED COLON STATIC VIRTUAL FRIEND OPERATOR THROW TEMPLATE
%token NATIVE INLINE
%token IFDEF IFNDEF ENDIF ELSE UNDEF IF DEFINED ELIF
%token RAW_MODE ALPHA_MODE TEXT DOC_DISABLE DOC_ENABLE STYLE LOCALSTYLE
%token TYPEMAP EXCEPT IMPORT ECHO NEW APPLY CLEAR DOCONLY
%token <ivalue> TITLE SECTION SUBSECTION SUBSUBSECTION
%token LESSTHAN GREATERTHAN
%token <id> USERDIRECTIVE
/* Objective C tokens */
%token OC_INTERFACE OC_END OC_PUBLIC OC_PRIVATE OC_PROTECTED OC_CLASS OC_IMPLEMENT OC_PROTOCOL
%left OR
%left XOR
%left AND
%left LSHIFT RSHIFT
%left PLUS MINUS
%left STAR SLASH
%left UMINUS NOT LNOT
%left DCOLON
%type <ivalue> extern array array2 parm_specifier parm_specifier_list;
%type <pl> parms ptail;
%type <p> parm parm_type;
%type <tmparm> typemap_parm tm_list tm_tail;
%type <id> pname cpptype base_specifier access_specifier typemap_name tm_method idstring;
%type <type> type opt_signed opt_unsigned strict_type;
%type <decl> declaration nested_decl;
%type <ivalue> stars cpp_const_expr;
%type <ilist> initlist base_list inherit;
%type <dtype> definetype definetail def_args;
%type <dtype> etype;
%type <dtype> expr;
%type <id> ename stylearg objc_inherit;
%type <dlist> stylelist styletail;
%type <type> objc_ret_type objc_arg_type;
%type <id> objc_protolist objc_separator;
%type <pl> objc_args;
%%
/* The productions of the grammar with their
associated semantic actions. */
program : {
{
int ii;
for (ii = 0; ii < 256; ii++) {
handler_stack[ii] = 0;
}
handler_stack[0] = comment_handler;
}
doc_stack[0] = doctitle;
} command {
CommentHandler::cleanup();
cplus_cleanup();
doc_entry = doctitle;
if (lang_init) {
lang->close();
}
if (te_index) {
fprintf(stderr,"%s : EOF. Missing #endif detected.\n", input_file);
FatalError();
}
}
;
command : command statement {
scanner_clear_start();
Error = 0;
}
| empty {
}
;
statement : INCLUDE idstring {
if (allow) {
// init_language();
doc_entry = 0;
// comment_handler->clear();
include_file($2);
}
}
/* %extern directive */
| WEXTERN idstring {
if (allow) {
int oldextern = WrapExtern;
// init_language();
doc_entry = 0;
// comment_handler->clear();
WrapExtern = 1;
if (include_file($2) >= 0) {
add_symbol("SWIGEXTERN",0,0);
} else {
WrapExtern = oldextern;
}
}
}
/* %import directive. Like %extern but calls out to a language module */
| IMPORT idstring {
if (allow) {
int oldextern = WrapExtern;
init_language();
doc_entry = 0;
WrapExtern = 1;
if (include_file($2) >= 0) {
add_symbol("SWIGEXTERN",0,0);
lang->import($2);
} else {
WrapExtern = oldextern;
}
}
}
/* %checkout directive. Like %include, but simply copies the file into the
current directory */
| CHECKOUT idstring {
if (allow) {
if ((checkout_file($2,$2)) == 0) {
fprintf(stderr,"%s checked out from the SWIG library.\n",$2);
}
}
}
/* An unknown C preprocessor statement. Just throw it away */
| POUND {
if (allow) {
doc_entry = 0;
if (Verbose) {
fprintf(stderr,"%s : Line %d. CPP %s ignored.\n", input_file, line_number,$1);
}
}
}
/* A variable declaration */
| extern type declaration array2 def_args {
if (allow) {
init_language();
if (Active_type) delete Active_type;
Active_type = new DataType($2);
Active_extern = $1;
$2->is_pointer += $3.is_pointer;
if ($4 > 0) {
$2->is_pointer++;
$2->status = STAT_READONLY;
$2->arraystr = copy_string(ArrayString);
}
if ($3.is_reference) {
fprintf(stderr,"%s : Line %d. Error. Linkage to C++ reference not allowed.\n", input_file, line_number);
FatalError();
} else {
if ($2->qualifier) {
if ((strcmp($2->qualifier,"const") == 0)) {
if ($5.type != T_ERROR)
create_constant($3.id, $2, $5.id);
} else
create_variable($1,$3.id,$2);
} else
create_variable($1,$3.id,$2);
}
}
delete $2;
} stail { }
/* Global variable that smells like a function pointer */
| extern strict_type LPAREN STAR {
skip_decl();
fprintf(stderr,"%s : Line %d. Function pointers not currently supported.\n",
input_file, line_number);
}
/* A static variable declaration (Ignored) */
| STATIC type declaration array2 def_args {
if (Verbose) {
fprintf(stderr,"static variable %s ignored.\n",$3.id);
}
Active_static = 1;
delete $2;
} stail {
Active_static = 0;
}
/* Global variable that smells like a function pointer */
| STATIC strict_type LPAREN STAR {
skip_decl();
fprintf(stderr,"%s : Line %d. Function pointers not currently supported.\n",
input_file, line_number);
}
/* A function declaration */
| extern type declaration LPAREN parms RPAREN cpp_const {
if (allow) {
init_language();
if (Active_type) delete Active_type;
Active_type = new DataType($2);
Active_extern = $1;
$2->is_pointer += $3.is_pointer;
$2->is_reference = $3.is_reference;
create_function($1, $3.id, $2, $5);
}
delete $2;
delete $5;
} stail { }
/* A function declaration with code after it */
| extern type declaration LPAREN parms RPAREN func_end {
if (allow) {
init_language();
$2->is_pointer += $3.is_pointer;
$2->is_reference = $3.is_reference;
create_function($1, $3.id, $2, $5);
}
delete $2;
delete $5;
};
/* A function declared without any return datatype */
| extern declaration LPAREN parms RPAREN cpp_const {
if (allow) {
init_language();
DataType *t = new DataType(T_INT);
t->is_pointer += $2.is_pointer;
t->is_reference = $2.is_reference;
create_function($1,$2.id,t,$4);
delete t;
}
} stail { };
/* A static function declaration code after it */
| STATIC type declaration LPAREN parms RPAREN func_end {
if ((allow) && (Inline)) {
if (strlen(CCode.get())) {
init_language();
$2->is_pointer += $3.is_pointer;
$2->is_reference = $3.is_reference;
create_function(0, $3.id, $2, $5);
}
}
delete $2;
delete $5;
};
/* A function with an explicit inline directive. Not safe to use inside a %inline block */
| INLINE type declaration LPAREN parms RPAREN func_end {
if (allow) {
init_language();
$2->is_pointer += $3.is_pointer;
$2->is_reference = $3.is_reference;
if (Inline) {
fprintf(stderr,"%s : Line %d. Repeated %%inline directive.\n",input_file,line_number);
FatalError();
} else {
if (strlen(CCode.get())) {
fprintf(f_header,"static ");
emit_extern_func($3.id,$2,$5,3,f_header);
fprintf(f_header,"%s\n",CCode.get());
}
create_function(0, $3.id, $2, $5);
}
}
delete $2;
delete $5;
};
/* A static function declaration (ignored) */
| STATIC type declaration LPAREN parms RPAREN cpp_const {
if (allow) {
if (Verbose) {
fprintf(stderr,"static function %s ignored.\n", $3.id);
}
}
Active_static = 1;
delete $2;
delete $5;
} stail {
Active_static = 0;
}
/* Enable Read-only mode */
| READONLY {
if (allow)
Status = Status | STAT_READONLY;
}
/* Enable Read-write mode */
| READWRITE {
if (allow)
Status = Status & ~STAT_READONLY;
}
/* New %name directive */
| NAME LPAREN ID RPAREN {
if (allow) {
strcpy(yy_rename,$3);
Rename_true = 1;
}
}
/* %rename directive */
| RENAME ID ID SEMI {
if (name_hash.lookup($2)) {
name_hash.remove($2);
}
name_hash.add($2,copy_string($3));
}
/* %new directive */
| NEW {
NewObject = 1;
} statement {
NewObject = 0;
}
/* Empty name directive. No longer allowed */
| NAME LPAREN RPAREN {
if (allow) {
fprintf(stderr,"%s : Lind %d. Empty %%name() is no longer supported.\n",
input_file, line_number);
FatalError();
}
} cpp {
Rename_true = 0;
}
/* A native wrapper function */
| NATIVE LPAREN ID RPAREN extern ID SEMI {
if (allow && (!WrapExtern)) {
init_language();
if (add_symbol($3,(DataType *) 0, (char *) 0)) {
fprintf(stderr,"%s : Line %d. Name of native function %s conflicts with previous declaration (ignored)\n",
input_file, line_number, $3);
} else {
doc_entry = new DocDecl($3,doc_stack[doc_stack_top]);
lang->add_native($3,$6);
}
}
}
| NATIVE LPAREN ID RPAREN extern type declaration LPAREN parms RPAREN SEMI {
if (allow && (!WrapExtern)) {
init_language();
$6->is_pointer += $7.is_pointer;
if (add_symbol($3,(DataType *) 0, (char *) 0)) {
fprintf(stderr,"%s : Line %d. Name of native function %s conflicts with previous declaration (ignored)\n",
input_file, line_number, $3);
} else {
if ($5) {
emit_extern_func($7.id, $6, $9, $5, f_header);
}
doc_entry = new DocDecl($3,doc_stack[doc_stack_top]);
lang->add_native($3,$7.id);
}
}
delete $6;
delete $9;
}
/* %title directive */
| TITLE STRING styletail {
if (allow && (!WrapExtern)) {
if (!title_init) {
title_init = 1;
doc_init = 1;
if (!comment_handler) {
comment_handler = new CommentHandler();
}
{
int ii;
for (ii = 0; ii < $3.count; ii++) {
comment_handler->style($3.names[ii],$3.values[ii]);
}
}
// Create a new title for documentation
{
int temp = line_number;
line_number = $1;
if (!doctitle)
doctitle = new DocTitle($2,0);
else {
doctitle->name = copy_string(title);
doctitle->line_number = $1;
doctitle->end_line = $1;
}
line_number = temp;
}
doctitle->usage = $2;
doc_entry = doctitle;
doc_stack[0] = doc_entry;
doc_stack_top = 0;
handler_stack[0] = comment_handler;
{
int ii;
for (ii = 0; ii < $3.count; ii++) {
doc_stack[doc_stack_top]->style($3.names[ii],$3.values[ii]);
}
}
} else {
// Ignore it
}
}
}
/* %section directive */
| SECTION STRING styletail {
if (allow && (!WrapExtern) && (!IgnoreDoc)) {
// Copy old comment handler
// if (handler_stack[1]) delete handler_stack[1];
handler_stack[1] = new CommentHandler(handler_stack[0]);
comment_handler = handler_stack[1];
{
int ii;
for (ii = 0; ii < $3.count; ii++) {
comment_handler->style($3.names[ii],$3.values[ii]);
}
}
{
int temp = line_number;
line_number = $1;
doc_entry = new DocSection($2,doc_stack[0]);
line_number = temp;
}
doc_stack_top = 1;
doc_stack[1] = doc_entry;
{
int ii;
for (ii = 0; ii < $3.count; ii++) {
doc_stack[doc_stack_top]->style($3.names[ii],$3.values[ii]);
}
}
}
}
/* %subsection directive */
| SUBSECTION STRING styletail {
if (allow && (!WrapExtern) && (!IgnoreDoc)) {
if (doc_stack_top < 1) {
fprintf(stderr,"%s : Line %d. Can't apply %%subsection here.\n", input_file,line_number);
FatalError();
} else {
// Copy old comment handler
// if (handler_stack[2]) delete handler_stack[2];
handler_stack[2] = new CommentHandler(handler_stack[1]);
comment_handler = handler_stack[2];
{
int ii;
for (ii = 0; ii < $3.count; ii++) {
comment_handler->style($3.names[ii],$3.values[ii]);
}
}
{
int temp = line_number;
line_number = $1;
doc_entry = new DocSection($2,doc_stack[1]);
line_number = temp;
}
doc_stack_top = 2;
doc_stack[2] = doc_entry;
{
int ii;
for (ii = 0; ii < $3.count; ii++) {
doc_stack[doc_stack_top]->style($3.names[ii],$3.values[ii]);
}
}
}
}
}
/* %subsubsection directive */
| SUBSUBSECTION STRING styletail {
if (allow && (!WrapExtern) && (!IgnoreDoc)) {
if (doc_stack_top < 2) {
fprintf(stderr,"%s : Line %d. Can't apply %%subsubsection here.\n", input_file,line_number);
FatalError();
} else {
// Copy old comment handler
// if (handler_stack[3]) delete handler_stack[3];
handler_stack[3] = new CommentHandler(handler_stack[2]);
comment_handler = handler_stack[3];
{
int ii;
for (ii = 0; ii < $3.count; ii++) {
comment_handler->style($3.names[ii],$3.values[ii]);
}
}
{
int temp = line_number;
line_number = $1;
doc_entry = new DocSection($2,doc_stack[2]);
line_number = temp;
}
doc_stack_top = 3;
doc_stack[3] = doc_entry;
{
int ii;
for (ii = 0; ii < $3.count; ii++) {
doc_stack[doc_stack_top]->style($3.names[ii],$3.values[ii]);
}
}
}
}
}
/* %alpha directive (obsolete) */
| ALPHA_MODE {
if (allow && (!WrapExtern)) {
fprintf(stderr,"%%alpha directive is obsolete. Use '%%style sort' instead.\n");
handler_stack[0]->style("sort",0);
doc_stack[0]->style("sort",0);
}
}
/* %raw directive (obsolete) */
| RAW_MODE {
if (allow && (!WrapExtern)) {
fprintf(stderr,"%%raw directive is obsolete. Use '%%style nosort' instead.\n");
handler_stack[0]->style("nosort",0);
doc_stack[0]->style("nosort",0);
}
}
| doc_enable { }
/* %text directive */
| TEXT HBLOCK {
if (allow && (!WrapExtern)) {
$2[strlen($2) - 1] = 0;
doc_entry = new DocText($2,doc_stack[doc_stack_top]);
doc_entry = 0;
}
}
| typedef_decl { }
/* Code insertion block */
| HBLOCK {
if (allow && (!WrapExtern)) {
init_language();
$1[strlen($1) - 1] = 0;
// fprintf(f_header,"#line %d \"%s\"\n", start_line, input_file);
fprintf(f_header, "%s\n", $1);
}
}
/* Super-secret undocumented for people who really know what's going on feature */
| WRAPPER HBLOCK {
if (allow && (!WrapExtern)) {
init_language();
$2[strlen($2) - 1] = 0;
fprintf(f_wrappers,"%s\n",$2);
}
}
/* Initialization code */
| INIT HBLOCK {
if (allow && (!WrapExtern)) {
init_language();
$2[strlen($2) -1] = 0;
fprintf(f_init,"%s\n", $2);
}
}
/* Inline block */
| INLINE HBLOCK {
if (allow && (!WrapExtern)) {
init_language();
$2[strlen($2) - 1] = 0;
fprintf(f_header, "%s\n", $2);
start_inline($2,start_line);
}
}
/* Echo mode */
| ECHO HBLOCK {
if (allow && (!WrapExtern)) {
fprintf(stderr,"%s\n", $2);
}
}
| ECHO STRING {
if (allow && (!WrapExtern)) {
fprintf(stderr,"%s\n", $2);
}
}
/* Disable code generation */
| DOCONLY {
DocOnly = 1;
}
/* Init directive--to avoid errors in other modules */
| INIT ID initlist {
if (allow) {
if (!module_init) {
lang->set_init($2);
module_init = 1;
init_language();
} else {
if (Verbose)
fprintf(stderr,"%s : Line %d. %%init %s ignored.\n",
input_file, line_number, $2);
}
if ($3.count > 0) {
fprintf(stderr,"%s : Line %d. Warning. Init list no longer supported.\n",
input_file,line_number);
}
}
for (i = 0; i < $3.count; i++)
if ($3.names[i]) delete [] $3.names[i];
delete [] $3.names;
}
/* Module directive */
| MODULE ID initlist {
if (allow) {
if ($3.count)
lang->set_module($2,$3.names);
else
lang->set_module($2,0);
module_init = 1;
init_language();
}
for (i = 0; i < $3.count; i++)
if ($3.names[i]) delete [] $3.names[i];
delete [] $3.names;
}
/* #define directive */
| DEFINE ID definetail {
if (allow) {
if (($3.type != T_ERROR) && ($3.type != T_SYMBOL)) {
init_language();
temp_typeptr = new DataType($3.type);
create_constant($2, temp_typeptr, $3.id);
delete temp_typeptr;
} else if ($3.type == T_SYMBOL) {
// Add a symbol to the SWIG symbol table
if (add_symbol($2,(DataType *) 0, (char *) 0)) {
fprintf(stderr,"%s : Line %d. Warning. Symbol %s already defined.\n",
input_file,line_number, $2);
}
}
}
}
/* A CPP Macro. Ignore (hopefully) */
| DEFINE MACRO {
if (Verbose) {
fprintf(stderr,"%s : Line %d. CPP Macro ignored.\n", input_file, line_number);
}
}
/* An undef directive */
| UNDEF ID {
remove_symbol($2);
}
/* Enumerations */
| extern ENUM ename LBRACE { scanner_clear_start(); } enumlist RBRACE SEMI {
if (allow) {
init_language();
if ($3) {
temp_type.type = T_INT;
temp_type.is_pointer = 0;
temp_type.implicit_ptr = 0;
sprintf(temp_type.name,"int");
temp_type.typedef_add($3,1);
}
}
}
/* A typdef'd enum. Pretty common in C headers */
| TYPEDEF ENUM ename LBRACE { scanner_clear_start(); } enumlist RBRACE ID {
if (allow) {
init_language();
temp_type.type = T_INT;
temp_type.is_pointer = 0;
temp_type.implicit_ptr = 0;
sprintf(temp_type.name,"int");
Active_typedef = new DataType(&temp_type);
temp_type.typedef_add($8,1);
}
} typedeflist { }
/* -----------------------------------------------------------------
typemap support.
These constructs are used to support type-maps.
----------------------------------------------------------------- */
/* Create a new typemap */
| TYPEMAP LPAREN ID COMMA tm_method RPAREN tm_list LBRACE {
TMParm *p;
skip_brace();
p = $7;
while (p) {
typemap_register($5,$3,p->p->t,p->p->name,CCode,p->args);
p = p->next;
}
delete $3;
delete $5;
}
/* Create a new typemap in current language */
| TYPEMAP LPAREN tm_method RPAREN tm_list LBRACE {
if (!typemap_lang) {
fprintf(stderr,"SWIG internal error. No typemap_lang specified.\n");
fprintf(stderr,"typemap on %s : Line %d. will be ignored.\n",input_file,line_number);
FatalError();
} else {
TMParm *p;
skip_brace();
p = $5;
while (p) {
typemap_register($3,typemap_lang,p->p->t,p->p->name,CCode,p->args);
p = p->next;
}
}
delete $3;
}
/* Clear a typemap */
| TYPEMAP LPAREN ID COMMA tm_method RPAREN tm_list SEMI {
TMParm *p;
p = $7;
while (p) {
typemap_clear($5,$3,p->p->t,p->p->name);
p = p->next;
}
delete $3;
delete $5;
}
/* Clear a typemap in current language */
| TYPEMAP LPAREN tm_method RPAREN tm_list SEMI {
if (!typemap_lang) {
fprintf(stderr,"SWIG internal error. No typemap_lang specified.\n");
fprintf(stderr,"typemap on %s : Line %d. will be ignored.\n",input_file,line_number);
FatalError();
} else {
TMParm *p;
p = $5;
while (p) {
typemap_clear($3,typemap_lang,p->p->t,p->p->name);
p = p->next;
}
}
delete $3;
}
/* Copy a typemap */
| TYPEMAP LPAREN ID COMMA tm_method RPAREN tm_list EQUAL typemap_parm SEMI {
TMParm *p;
p = $7;
while (p) {
typemap_copy($5,$3,$9->p->t,$9->p->name,p->p->t,p->p->name);
p = p->next;
}
delete $3;
delete $5;
delete $9->p;
delete $9;
}
/* Copy typemap in current language */
| TYPEMAP LPAREN tm_method RPAREN tm_list EQUAL typemap_parm SEMI {
if (!typemap_lang) {
fprintf(stderr,"SWIG internal error. No typemap_lang specified.\n");
fprintf(stderr,"typemap on %s : Line %d. will be ignored.\n",input_file,line_number);
FatalError();
} else {
TMParm *p;
p = $5;
while (p) {
typemap_copy($3,typemap_lang,$7->p->t,$7->p->name,p->p->t,p->p->name);
p = p->next;
}
}
delete $3;
delete $7->p;
delete $7;
}
/* -----------------------------------------------------------------
apply and clear support (for typemaps)
----------------------------------------------------------------- */
| APPLY typemap_parm LBRACE tm_list RBRACE {
TMParm *p;
p = $4;
while(p) {
typemap_apply($2->p->t,$2->p->name,p->p->t,p->p->name);
p = p->next;
}
delete $4;
delete $2->args;
delete $2;
}
| CLEAR tm_list SEMI {
TMParm *p;
p = $2;
while (p) {
typemap_clear_apply(p->p->t, p->p->name);
p = p->next;
}
}
/* -----------------------------------------------------------------
exception support
These constructs are used to define exceptions
----------------------------------------------------------------- */
/* An exception definition */
| EXCEPT LPAREN ID RPAREN LBRACE {
skip_brace();
fragment_register("except",$3, CCode);
delete $3;
}
/* A Generic Exception (no language specified */
| EXCEPT LBRACE {
skip_brace();
fragment_register("except",typemap_lang, CCode);
}
/* Clear an exception */
| EXCEPT LPAREN ID RPAREN SEMI {
fragment_clear("except",$3);
}
/* Generic clear */
| EXCEPT SEMI {
fragment_clear("except",typemap_lang);
}
/* Miscellaenous stuff */
| SEMI { }
| cpp { }
| objective_c { }
| error {
if (!Error) {
{
static int last_error_line = -1;
if (last_error_line != line_number) {
fprintf(stderr,"%s : Line %d. Syntax error in input.\n", input_file, line_number);
FatalError();
last_error_line = line_number;
// Try to make some kind of recovery.
skip_decl();
}
Error = 1;
}
}
}
/* A an extern C type declaration. Does nothing, but is ignored */
| EXTERN STRING LBRACE command RBRACE { }
| cond_compile { }
/* Officially, this directive doesn't exist yet */
| pragma { }
/* %style directive. This applies to all current styles */
| STYLE stylelist {
{
int ii,jj;
for (ii = 0; ii < $2.count; ii++) {
comment_handler->style($2.names[ii],$2.values[ii]);
for (jj = 0; jj < doc_stack_top; jj++)
doc_stack[jj]->style($2.names[ii],$2.values[ii]);
if (doctitle)
doctitle->style($2.names[ii],$2.values[ii]);
doc->style($2.names[ii],$2.values[ii]);
}
}
}
/* %localstyle directive. This applies only to the current style */
| LOCALSTYLE stylelist {
{
int ii;
for (ii = 0; ii < $2.count; ii++) {
comment_handler = new CommentHandler(comment_handler);
handler_stack[doc_stack_top] = comment_handler;
comment_handler->style($2.names[ii],$2.values[ii]);
doc_stack[doc_stack_top]->style($2.names[ii],$2.values[ii]);
}
}
}
/* User defined directive */
| user_directive{ }
;
/* Dcumentation disable/enable */
doc_enable : DOC_DISABLE {
if (allow) {
if (IgnoreDoc) {
/* Already in a disabled documentation */
doc_scope++;
} else {
if (Verbose)
fprintf(stderr,"%s : Line %d. Documentation disabled.\n", input_file, line_number);
IgnoreDoc = 1;
doc_scope = 1;
}
}
}
/* %enabledoc directive */
| DOC_ENABLE {
if (allow) {
if (IgnoreDoc) {
if (doc_scope > 1) {
doc_scope--;
} else {
if (Verbose)
fprintf(stderr,"%s : Line %d. Documentation enabled.\n", input_file, line_number);
IgnoreDoc = 0;
doc_scope = 0;
}
}
}
}
;
/* Note : This really needs to be re-done */
/* A typedef with pointers */
typedef_decl : TYPEDEF type declaration {
if (allow) {
init_language();
/* Add a new typedef */
Active_typedef = new DataType($2);
$2->is_pointer += $3.is_pointer;
$2->typedef_add($3.id);
/* If this is %typedef, add it to the header */
if ($1)
fprintf(f_header,"typedef %s %s;\n", $2->print_full(), $3.id);
cplus_register_type($3.id);
}
} typedeflist { };
/* A rudimentary typedef involving function pointers */
| TYPEDEF type LPAREN STAR pname RPAREN LPAREN parms RPAREN SEMI {
if (allow) {
init_language();
/* Typedef'd pointer */
if ($1) {
sprintf(temp_name,"(*%s)",$5);
fprintf(f_header,"typedef ");
emit_extern_func(temp_name, $2,$8,0,f_header);
}
strcpy($2->name,"<function ptr>");
$2->type = T_USER;
$2->is_pointer = 1;
$2->typedef_add($5,1);
cplus_register_type($5);
}
delete $2;
delete $5;
delete $8;
}
/* A typedef involving function pointers again */
| TYPEDEF type stars LPAREN STAR pname RPAREN LPAREN parms RPAREN SEMI {
if (allow) {
init_language();
if ($1) {
$2->is_pointer += $3;
sprintf(temp_name,"(*%s)",$6);
fprintf(f_header,"typedef ");
emit_extern_func(temp_name, $2,$9,0,f_header);
}
/* Typedef'd pointer */
strcpy($2->name,"<function ptr>");
$2->type = T_USER;
$2->is_pointer = 1;
$2->typedef_add($6,1);
cplus_register_type($6);
}
delete $2;
delete $6;
delete $9;
}
/* A typedef involving arrays */
| TYPEDEF type declaration array {
if (allow) {
init_language();
Active_typedef = new DataType($2);
// This datatype is going to be readonly
$2->status = STAT_READONLY | STAT_REPLACETYPE;
$2->is_pointer += $3.is_pointer;
// Turn this into a "pointer" corresponding to the array
$2->is_pointer++;
$2->arraystr = copy_string(ArrayString);
$2->typedef_add($3.id);
fprintf(stderr,"%s : Line %d. Warning. Array type %s will be read-only without a typemap\n",input_file,line_number, $3.id);
cplus_register_type($3.id);
}
} typedeflist { }
;
/* ------------------------------------------------------------------------
Typedef list
The following rules are used to manage typedef lists. Only a temporary
hack until the SWIG 2.0 parser gets online.
Active_typedef contains the datatype of the last typedef (if applicable)
------------------------------------------------------------------------ */
typedeflist : COMMA declaration typedeflist {
if (allow) {
if (Active_typedef) {
DataType *t;
t = new DataType(Active_typedef);
t->is_pointer += $2.is_pointer;
t->typedef_add($2.id);
cplus_register_type($2.id);
delete t;
}
}
}
| COMMA declaration array {
DataType *t;
t = new DataType(Active_typedef);
t->status = STAT_READONLY | STAT_REPLACETYPE;
t->is_pointer += $2.is_pointer + 1;
t->arraystr = copy_string(ArrayString);
t->typedef_add($2.id);
cplus_register_type($2.id);
delete t;
fprintf(stderr,"%s : Line %d. Warning. Array type %s will be read-only without a typemap.\n",input_file,line_number, $2.id);
}
| empty { }
;
/* ----------------------------------------------------------------------------------
Conditional Compilation
SWIG supports the following constructs
#ifdef
#ifndef
#else
#endif
#if defined(ID)
#if ! defined(ID)
#elif
#if, and #elif are a little weak in this implementation
---------------------------------------------------------------------------------- */
/* #ifdef directive */
cond_compile : IFDEF ID {
/* Push old if-then-else status */
if_push();
/* Look a symbol up in the symbol table */
if (lookup_symbol($2)) {
in_then = 1;
in_else = 0;
allow = 1 & prev_allow;
} else {
/* Condition is false. Skip over whatever is in this block */
in_else = skip_cond(1);
if (in_else == -1) {
/* Unrecoverable error */
SWIG_exit(1);
}
if (!in_else) {
if_pop(); // Pop out. Reached end of block
} else {
allow = prev_allow;
in_then = 0;
}
}
}
/* #ifndef directive */
| IFNDEF ID {
if_push();
if (lookup_symbol($2)) {
/* Condition is false. Skip over whatever is in this block */
in_else = skip_cond(1);
if (in_else == -1) {
/* Unrecoverable error */
SWIG_exit(1);
}
if (!in_else) {
if_pop(); // Pop out. Reached end of block
} else {
allow = prev_allow;
in_then = 0;
}
} else {
in_then = 1;
in_else = 0;
allow = 1 & prev_allow;
}
}
/* #else directive */
| ELSE {
if ((!in_then) || (in_else)) {
fprintf(stderr,"%s : Line %d. Misplaced else\n", input_file, line_number);
FatalError();
} else {
in_then = 0;
in_else = 1;
if (allow) {
allow = 0;
/* Skip over rest of the conditional */
skip_cond(0);
if_pop();
} else {
allow = 1;
}
allow = allow & prev_allow;
}
}
/* #endif directive */
| ENDIF {
if ((!in_then) && (!in_else)) {
fprintf(stderr,"%s : Line %d. Misplaced endif\n", input_file, line_number);
FatalError();
} else {
if_pop();
}
}
/* #if */
| IF cpp_const_expr {
/* Push old if-then-else status */
if_push();
if ($2) {
in_then = 1;
in_else = 0;
allow = 1 & prev_allow;
} else {
/* Condition is false. Skip over whatever is in this block */
in_else = skip_cond(1);
if (in_else == -1) {
/* Unrecoverable error */
SWIG_exit(1);
}
if (!in_else) {
if_pop(); // Pop out. Reached end of block
} else {
allow = prev_allow;
in_then = 0;
}
}
}
/* #elif. We treat this identical to an #if. Abit of a hack, but what
the hell. */
| ELIF cpp_const_expr {
/* have to pop old if clause off */
if_pop();
/* Push old if-then-else status */
if_push();
if ($2) {
in_then = 1;
in_else = 0;
allow = 1 & prev_allow;
} else {
/* Condition is false. Skip over whatever is in this block */
in_else = skip_cond(1);
if (in_else == -1) {
/* Unrecoverable error */
SWIG_exit(1);
}
if (!in_else) {
if_pop(); // Pop out. Reached end of block
} else {
allow = prev_allow;
in_then = 0;
}
}
}
;
/* C preprocessor expression (only used for conditional compilation */
cpp_const_expr : DEFINED LPAREN ID RPAREN {
/* Look ID up in the symbol table */
if (lookup_symbol($3)) {
$$ = 1;
} else {
$$ = 0;
}
}
| DEFINED ID {
if (lookup_symbol($2)) {
$$ = 1;
} else {
$$ = 0;
}
}
| LNOT cpp_const_expr {
if ($2) $$ = 0;
else $$ = 1;
}
;
pragma : PRAGMA LPAREN ID COMMA ID stylearg RPAREN {
if (allow && (!WrapExtern))
lang->pragma($3,$5,$6);
fprintf(stderr,"%s : Line %d. Warning. '%%pragma(lang,opt=value)' syntax is obsolete.\n",
input_file,line_number);
fprintf(stderr," Use '%%pragma(lang) opt=value' instead.\n");
}
| PRAGMA ID stylearg {
if (allow && (!WrapExtern))
swig_pragma($2,$3);
}
| PRAGMA LPAREN ID RPAREN ID stylearg {
if (allow && (!WrapExtern))
lang->pragma($3,$5,$6);
}
;
/* Allow lists of variables and functions to be built up */
stail : SEMI { }
| COMMA declaration array2 def_args {
if (allow) {
init_language();
temp_typeptr = new DataType(Active_type);
temp_typeptr->is_pointer += $2.is_pointer;
if ($3 > 0) {
temp_typeptr->is_pointer++;
temp_typeptr->status = STAT_READONLY;
temp_typeptr->arraystr = copy_string(ArrayString);
}
if ($2.is_reference) {
fprintf(stderr,"%s : Line %d. Error. Linkage to C++ reference not allowed.\n", input_file, line_number);
FatalError();
} else {
if (temp_typeptr->qualifier) {
if ((strcmp(temp_typeptr->qualifier,"const") == 0)) {
/* Okay. This is really some sort of C++ constant here. */
if ($4.type != T_ERROR)
create_constant($2.id, temp_typeptr, $4.id);
} else
create_variable(Active_extern,$2.id, temp_typeptr);
} else
create_variable(Active_extern, $2.id, temp_typeptr);
}
delete temp_typeptr;
}
} stail { }
| COMMA declaration LPAREN parms RPAREN cpp_const {
if (allow) {
init_language();
temp_typeptr = new DataType(Active_type);
temp_typeptr->is_pointer += $2.is_pointer;
temp_typeptr->is_reference = $2.is_reference;
create_function(Active_extern, $2.id, temp_typeptr, $4);
delete temp_typeptr;
}
delete $4;
} stail { }
;
definetail : definetype ENDDEF {
$$ = $1;
}
| ENDDEF {
$$.type = T_SYMBOL;
}
| error ENDDEF {
if (Verbose)
fprintf(stderr,"%s : Line %d. Warning. Unable to parse #define (ignored)\n", input_file, line_number);
$$.type = T_ERROR;
}
;
extern : EXTERN { $$ = 1; }
| empty {$$ = 0; }
| EXTERN STRING {
if (strcmp($2,"C") == 0) {
$$ = 2;
} else {
fprintf(stderr,"%s : Line %d. Unrecognized extern type \"%s\" (ignored).\n", input_file, line_number, $2);
FatalError();
}
}
;
/* End of a function declaration. Allows C++ "const" directive and inline code */
func_end : cpp_const LBRACE { skip_brace(); }
/* | LBRACE { skip_brace(); } */
;
/* ------------------------------------------------------------------------------
Function parameter lists
------------------------------------------------------------------------------ */
parms : parm ptail {
if (($1->t->type != T_VOID) || ($1->t->is_pointer))
$2->insert($1,0);
$$ = $2;
delete $1;
}
| empty { $$ = new ParmList;}
;
ptail : COMMA parm ptail {
$3->insert($2,0);
$$ = $3;
delete $2;
}
| empty { $$ = new ParmList;}
;
parm : parm_type {
$$ = $1;
if (typemap_check("ignore",typemap_lang,$$->t,$$->name))
$$->ignore = 1;
}
| parm_specifier_list parm_type {
$$ = $2;
$$->call_type = $$->call_type | $1;
if (InArray && ($$->call_type & CALL_VALUE)) {
fprintf(stderr,"%s : Line %d. Error. Can't use %%val with an array.\n", input_file, line_number);
FatalError();
}
if (!$$->t->is_pointer) {
fprintf(stderr,"%s : Line %d. Error. Can't use %%val or %%out with a non-pointer argument.\n", input_file, line_number);
FatalError();
} else {
$$->t->is_pointer--;
}
}
parm_type : type pname {
if (InArray) {
$1->is_pointer++;
if (Verbose) {
fprintf(stderr,"%s : Line %d. Warning. Array %s", input_file, line_number, $1->print_type());
print_array();
fprintf(stderr," has been converted to %s.\n", $1->print_type());
}
// Add array string to the type
$1->arraystr = copy_string(ArrayString.get());
}
$$ = new Parm($1,$2);
$$->call_type = 0;
$$->defvalue = DefArg;
if (($1->type == T_USER) && !($1->is_pointer)) {
if (Verbose)
fprintf(stderr,"%s : Line %d. Warning : Parameter of type '%s'\nhas been remapped to '%s *' and will be called using *((%s *) ptr).\n",
input_file, line_number, $1->name, $1->name, $1->name);
$$->call_type = CALL_REFERENCE;
$$->t->is_pointer++;
}
delete $1;
delete $2;
}
| type stars pname {
$$ = new Parm($1,$3);
$$->t->is_pointer += $2;
$$->call_type = 0;
$$->defvalue = DefArg;
if (InArray) {
$$->t->is_pointer++;
if (Verbose) {
fprintf(stderr,"%s : Line %d. Warning. Array %s", input_file, line_number, $$->t->print_type());
print_array();
fprintf(stderr," has been converted to %s.\n", $$->t->print_type());
}
// Add array string to the type
$$->t->arraystr = copy_string(ArrayString.get());
}
delete $1;
delete $3;
}
| type AND pname {
$$ = new Parm($1,$3);
$$->t->is_reference = 1;
$$->call_type = 0;
$$->t->is_pointer++;
$$->defvalue = DefArg;
if (!CPlusPlus) {
fprintf(stderr,"%s : Line %d. Warning. Use of C++ Reference detected. Use the -c++ option.\n", input_file, line_number);
}
delete $1;
delete $3;
}
| type LPAREN stars pname RPAREN LPAREN parms RPAREN {
fprintf(stderr,"%s : Line %d. Error. Function pointer not allowed (remap with typedef).\n", input_file, line_number);
FatalError();
$$ = new Parm($1,$4);
$$->t->type = T_ERROR;
$$->name = copy_string($4);
strcpy($$->t->name,"<function ptr>");
delete $1;
delete $4;
delete $7;
}
| PERIOD PERIOD PERIOD {
fprintf(stderr,"%s : Line %d. Variable length arguments not supported (ignored).\n", input_file, line_number);
$$ = new Parm(new DataType(T_INT),"varargs");
$$->t->type = T_ERROR;
$$->name = copy_string("varargs");
strcpy($$->t->name,"<varargs>");
FatalError();
}
;
pname : ID def_args {
$$ = $1;
InArray = 0;
if ($2.type == T_CHAR)
DefArg = copy_string(ConstChar);
else
DefArg = copy_string($2.id);
if ($2.id) delete $2.id;
}
| ID array {
$$ = $1;
InArray = $2;
DefArg = 0;
}
| array {
$$ = new char[1];
$$[0] = 0;
InArray = $1;
DefArg = 0;
}
| empty { $$ = new char[1];
$$[0] = 0;
InArray = 0;
DefArg = 0;
}
;
def_args : EQUAL definetype { $$ = $2; }
| EQUAL AND ID {
$$.id = new char[strlen($3)+2];
$$.id[0] = '&';
strcpy(&$$.id[1], $3);
$$.type = T_USER;
}
| EQUAL LBRACE {
skip_brace();
$$.id = 0; $$.type = T_INT;
}
| COLON NUM_INT {
}
| empty {$$.id = 0; $$.type = T_INT;}
;
parm_specifier : CVALUE { $$ = CALL_VALUE; }
| COUT { $$ = CALL_OUTPUT; }
;
parm_specifier_list : parm_specifier_list parm_specifier {
$$ = $1 | $2;
}
| parm_specifier {
$$ = $1;
}
;
/* Declaration must be an identifier, possibly preceded by a * for pointer types */
declaration : ID { $$.id = $1;
$$.is_pointer = 0;
$$.is_reference = 0;
}
| stars ID {
$$.id = $2;
$$.is_pointer = $1;
$$.is_reference = 0;
}
| AND ID {
$$.id = $2;
$$.is_pointer = 1;
$$.is_reference = 1;
if (!CPlusPlus) {
fprintf(stderr,"%s : Line %d. Warning. Use of C++ Reference detected. Use the -c++ option.\n", input_file, line_number);
}
}
;
stars : STAR empty { $$ = 1; }
| STAR stars { $$ = $2 + 1;}
;
array : LBRACKET RBRACKET array2 {
$$ = $3 + 1;
"[]" >> ArrayString;
}
| LBRACKET expr RBRACKET array2 {
$$ = $4 + 1;
"]" >> ArrayString;
$2.id >> ArrayString;
"[" >> ArrayString;
}
;
array2 : array {
$$ = $1;
}
| empty { $$ = 0;
ArrayString = "";
}
;
/* Data type must be a built in type or an identifier for user-defined types
This type can be preceded by a modifier. */
type : TYPE_INT {
$$ = $1;
}
| TYPE_SHORT opt_int {
$$ = $1;
}
| TYPE_LONG opt_int {
$$ = $1;
}
| TYPE_CHAR {
$$ = $1;
}
| TYPE_BOOL {
$$ = $1;
}
| TYPE_FLOAT {
$$ = $1;
}
| TYPE_DOUBLE {
$$ = $1;
}
| TYPE_VOID {
$$ = $1;
}
| TYPE_SIGNED opt_signed {
if ($2) $$ = $2;
else $$ = $1;
}
| TYPE_UNSIGNED opt_unsigned {
if ($2) $$ = $2;
else $$ = $1;
}
| TYPE_TYPEDEF objc_protolist {
$$ = $1;
if (strlen($2) > 0) {
if ((strlen($2) + strlen($$->name)) >= MAX_NAME) {
fprintf(stderr,"%s : Line %d. Fatal error. Type-name is too long!\n",
input_file, line_number);
} else {
strcat($$->name,$2);
}
}
}
| ID objc_protolist {
$$ = new DataType;
strcpy($$->name,$1);
$$->type = T_USER;
/* Do a typedef lookup */
$$->typedef_resolve();
if (strlen($2) > 0) {
if ((strlen($2) + strlen($$->name)) >= MAX_NAME) {
fprintf(stderr,"%s : Line %d. Fatal error. Type-name is too long!\n",
input_file, line_number);
} else {
strcat($$->name,$2);
}
}
}
| CONST type {
$$ = $2;
$$->qualifier = new char[6];
strcpy($$->qualifier,"const");
}
| cpptype ID {
$$ = new DataType;
sprintf($$->name,"%s %s",$1, $2);
$$->type = T_USER;
}
| ID DCOLON ID {
$$ = new DataType;
sprintf($$->name,"%s::%s",$1,$3);
$$->type = T_USER;
$$->typedef_resolve();
}
/* This declaration causes a shift-reduce conflict. Unresolved for now */
| DCOLON ID {
$$ = new DataType;
sprintf($$->name,"%s", $2);
$$->type = T_USER;
$$->typedef_resolve(1);
}
| ENUM ID {
$$ = new DataType;
sprintf($$->name,"enum %s", $2);
$$->type = T_INT;
$$->typedef_resolve(1);
}
;
/* type specification without ID symbol. Used in some cases to prevent shift-reduce conflicts */
strict_type : TYPE_INT {
$$ = $1;
}
| TYPE_SHORT opt_int {
$$ = $1;
}
| TYPE_LONG opt_int {
$$ = $1;
}
| TYPE_CHAR {
$$ = $1;
}
| TYPE_BOOL {
$$ = $1;
}
| TYPE_FLOAT {
$$ = $1;
}
| TYPE_DOUBLE {
$$ = $1;
}
| TYPE_VOID {
$$ = $1;
}
| TYPE_SIGNED opt_signed {
if ($2) $$ = $2;
else $$ = $1;
}
| TYPE_UNSIGNED opt_unsigned {
if ($2) $$ = $2;
else $$ = $1;
}
| TYPE_TYPEDEF objc_protolist {
$$ = $1;
strcat($$->name,$2);
}
| CONST type {
$$ = $2;
$$->qualifier = new char[6];
strcpy($$->qualifier,"const");
}
| cpptype ID {
$$ = new DataType;
sprintf($$->name,"%s %s",$1, $2);
$$->type = T_USER;
}
;
/* Optional signed types */
opt_signed : empty {
$$ = (DataType *) 0;
}
| TYPE_INT {
$$ = $1;
$$->type = T_INT;
sprintf(temp_name,"signed %s",$1->name);
strcpy($$->name,temp_name);
}
| TYPE_SHORT opt_int {
$$ = $1;
$$->type = T_SHORT;
sprintf(temp_name,"signed %s",$1->name);
strcpy($$->name,temp_name);
}
| TYPE_LONG opt_int {
$$ = $1;
$$->type = T_LONG;
sprintf(temp_name,"signed %s",$1->name);
strcpy($$->name,temp_name);
}
| TYPE_CHAR {
$$ = $1;
$$->type = T_SCHAR;
sprintf(temp_name,"signed %s",$1->name);
strcpy($$->name,temp_name);
}
;
/* Optional unsigned types */
opt_unsigned : empty {
$$ = (DataType *) 0;
}
| TYPE_INT {
$$ = $1;
$$->type = T_UINT;
sprintf(temp_name,"unsigned %s",$1->name);
strcpy($$->name,temp_name);
}
| TYPE_SHORT opt_int {
$$ = $1;
$$->type = T_USHORT;
sprintf(temp_name,"unsigned %s",$1->name);
strcpy($$->name,temp_name);
}
| TYPE_LONG opt_int {
$$ = $1;
$$->type = T_ULONG;
sprintf(temp_name,"unsigned %s",$1->name);
strcpy($$->name,temp_name);
}
| TYPE_CHAR {
$$ = $1;
$$->type = T_UCHAR;
sprintf(temp_name,"unsigned %s",$1->name);
strcpy($$->name,temp_name);
}
;
opt_int : TYPE_INT { }
| empty { }
;
definetype : { scanner_check_typedef(); } expr {
$$ = $2;
scanner_ignore_typedef();
if (ConstChar) delete ConstChar;
ConstChar = 0;
}
| STRING {
$$.id = $1;
$$.type = T_CHAR;
if (ConstChar) delete ConstChar;
ConstChar = new char[strlen($1)+3];
sprintf(ConstChar,"\"%s\"",$1);
}
| CHARCONST {
$$.id = $1;
$$.type = T_CHAR;
if (ConstChar) delete ConstChar;
ConstChar = new char[strlen($1)+3];
sprintf(ConstChar,"'%s'",$1);
}
;
/* Initialization function links */
initlist : initlist COMMA ID {
$$ = $1;
$$.names[$$.count] = copy_string($3);
$$.count++;
$$.names[$$.count] = (char *) 0;
}
| empty {
$$.names = new char *[NI_NAMES];
$$.count = 0;
for (i = 0; i < NI_NAMES; i++)
$$.names[i] = (char *) 0;
}
;
/* Some stuff for handling enums */
ename : ID { $$ = $1; }
| empty { $$ = (char *) 0;}
;
/* SWIG enum list.
*/
enumlist : enumlist COMMA edecl {}
| edecl {}
;
edecl : ID {
temp_typeptr = new DataType(T_INT);
create_constant($1, temp_typeptr, $1);
delete temp_typeptr;
}
| ID EQUAL { scanner_check_typedef();} etype {
temp_typeptr = new DataType($4.type);
// Use enum name instead of value
// OLD create_constant($1, temp_typeptr, $4.id);
create_constant($1, temp_typeptr, $1);
delete temp_typeptr;
}
| cond_compile edecl { }
| empty { }
;
etype : expr {
$$ = $1;
if (($$.type != T_INT) && ($$.type != T_UINT) &&
($$.type != T_LONG) && ($$.type != T_ULONG) &&
($$.type != T_SHORT) && ($$.type != T_USHORT) &&
($$.type != T_SCHAR) && ($$.type != T_UCHAR)) {
fprintf(stderr,"%s : Lind %d. Type error. Expecting an int\n",
input_file, line_number);
FatalError();
}
}
| CHARCONST {
$$.id = $1;
$$.type = T_CHAR;
}
;
/* Arithmetic expressions. Used for constants and other cool stuff.
Really, we're not doing anything except string concatenation, but
this does allow us to parse many constant declarations.
*/
expr : NUM_INT {
$$.id = $1;
$$.type = T_INT;
}
| NUM_FLOAT {
$$.id = $1;
$$.type = T_DOUBLE;
}
| NUM_UNSIGNED {
$$.id = $1;
$$.type = T_UINT;
}
| NUM_LONG {
$$.id = $1;
$$.type = T_LONG;
}
| NUM_ULONG {
$$.id = $1;
$$.type = T_ULONG;
}
| SIZEOF LPAREN type RPAREN {
$$.id = new char[strlen($3->name)+9];
sprintf($$.id,"sizeof(%s)", $3->name);
$$.type = T_INT;
}
| LPAREN strict_type RPAREN expr %prec UMINUS {
$$.id = new char[strlen($4.id)+strlen($2->name)+3];
sprintf($$.id,"(%s)%s",$2->name,$4.id);
$$.type = $2->type;
}
| ID {
$$.id = lookup_symvalue($1);
if ($$.id == (char *) 0)
$$.id = $1;
else {
$$.id = new char[strlen($$.id)+3];
sprintf($$.id,"(%s)",lookup_symvalue($1));
}
temp_typeptr = lookup_symtype($1);
if (temp_typeptr) $$.type = temp_typeptr->type;
else $$.type = T_INT;
}
| ID DCOLON ID {
$$.id = new char[strlen($1)+strlen($3)+3];
sprintf($$.id,"%s::%s",$1,$3);
$$.type = T_INT;
delete $1;
delete $3;
}
| expr PLUS expr {
E_BINARY($$.id,$1.id,$3.id,"+");
$$.type = promote($1.type,$3.type);
delete $1.id;
delete $3.id;
}
| expr MINUS expr {
E_BINARY($$.id,$1.id,$3.id,"-");
$$.type = promote($1.type,$3.type);
delete $1.id;
delete $3.id;
}
| expr STAR expr {
E_BINARY($$.id,$1.id,$3.id,"*");
$$.type = promote($1.type,$3.type);
delete $1.id;
delete $3.id;
}
| expr SLASH expr {
E_BINARY($$.id,$1.id,$3.id,"/");
$$.type = promote($1.type,$3.type);
delete $1.id;
delete $3.id;
}
| expr AND expr {
E_BINARY($$.id,$1.id,$3.id,"&");
$$.type = promote($1.type,$3.type);
if (($1.type == T_DOUBLE) || ($3.type == T_DOUBLE)) {
fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number);
FatalError();
}
delete $1.id;
delete $3.id;
}
| expr OR expr {
E_BINARY($$.id,$1.id,$3.id,"|");
$$.type = promote($1.type,$3.type);
if (($1.type == T_DOUBLE) || ($3.type == T_DOUBLE)) {
fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number);
FatalError();
}
$$.type = T_INT;
delete $1.id;
delete $3.id;
}
| expr XOR expr {
E_BINARY($$.id,$1.id,$3.id,"^");
$$.type = promote($1.type,$3.type);
if (($1.type == T_DOUBLE) || ($3.type == T_DOUBLE)) {
fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number);
FatalError();
}
$$.type = T_INT;
delete $1.id;
delete $3.id;
}
| expr LSHIFT expr {
E_BINARY($$.id,$1.id,$3.id,"<<");
$$.type = promote($1.type,$3.type);
if (($1.type == T_DOUBLE) || ($3.type == T_DOUBLE)) {
fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number);
FatalError();
}
$$.type = T_INT;
delete $1.id;
delete $3.id;
}
| expr RSHIFT expr {
E_BINARY($$.id,$1.id,$3.id,">>");
$$.type = promote($1.type,$3.type);
if (($1.type == T_DOUBLE) || ($3.type == T_DOUBLE)) {
fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number);
FatalError();
}
$$.type = T_INT;
delete $1.id;
delete $3.id;
}
| MINUS expr %prec UMINUS {
$$.id = new char[strlen($2.id)+2];
sprintf($$.id,"-%s",$2.id);
$$.type = $2.type;
delete $2.id;
}
| NOT expr {
$$.id = new char[strlen($2.id)+2];
sprintf($$.id,"~%s",$2.id);
if ($2.type == T_DOUBLE) {
fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number);
FatalError();
}
$$.type = $2.type;
delete $2.id;
}
| LPAREN expr RPAREN {
$$.id = new char[strlen($2.id)+3];
sprintf($$.id,"(%s)", $2.id);
$$.type = $2.type;
delete $2.id;
}
;
/****************************************************************/
/* C++ Support */
/****************************************************************/
cpp : cpp_class { }
| cpp_other {}
;
cpp_class :
/* A class/struct/union definition */
extern cpptype ID inherit LBRACE {
char *iname;
if (allow) {
init_language();
DataType::new_scope();
sprintf(temp_name,"CPP_CLASS:%s\n",$3);
if (add_symbol(temp_name, (DataType *) 0, (char *) 0)) {
fprintf(stderr,"%s : Line %d. Error. %s %s is multiply defined.\n", input_file, line_number, $2, $3);
FatalError();
}
if ((!CPlusPlus) && (strcmp($2,"class") == 0))
fprintf(stderr,"%s : Line %d. *** WARNING ***. C++ mode is disabled (enable using -c++)\n", input_file, line_number);
iname = make_name($3);
doc_entry = new DocClass(iname, doc_parent());
if (iname == $3)
cplus_open_class($3, 0, $2);
else
cplus_open_class($3, iname, $2);
if (strcmp($2,"class") == 0)
cplus_mode = CPLUS_PRIVATE;
else
cplus_mode = CPLUS_PUBLIC;
doc_stack_top++;
doc_stack[doc_stack_top] = doc_entry;
scanner_clear_start();
nested_list = 0;
// Merge in scope from base classes
cplus_inherit_scope($4.count,$4.names);
}
} cpp_members RBRACE {
if (allow) {
if ($4.names) {
if (strcmp($2,"union") != 0)
cplus_inherit($4.count, $4.names);
else {
fprintf(stderr,"%s : Line %d. Inheritance not allowed for unions.\n",input_file, line_number);
FatalError();
}
}
// Clean up the inheritance list
if ($4.names) {
int j;
for (j = 0; j < $4.count; j++) {
if ($4.names[j]) delete [] $4.names[j];
}
delete [] $4.names;
}
// Dumped nested declarations (if applicable)
dump_nested($3);
// Save and collapse current scope
cplus_register_scope(DataType::collapse_scope($3));
// Restore the original doc entry for this class
doc_entry = doc_stack[doc_stack_top];
cplus_class_close((char *) 0);
doc_entry = 0;
// Bump the documentation stack back down
doc_stack_top--;
cplus_mode = CPLUS_PUBLIC;
}
}
/* Class with a typedef */
| TYPEDEF cpptype ID inherit LBRACE {
if (allow) {
char *iname;
init_language();
DataType::new_scope();
sprintf(temp_name,"CPP_CLASS:%s\n",$3);
if (add_symbol(temp_name, (DataType *) 0, (char *) 0)) {
fprintf(stderr,"%s : Line %d. Error. %s %s is multiply defined.\n", input_file, line_number, $2, $3);
FatalError();
}
if ((!CPlusPlus) && (strcmp($2,"class") == 0))
fprintf(stderr,"%s : Line %d. *** WARNING ***. C++ mode is disabled (enable using -c++)\n", input_file, line_number);
iname = make_name($3);
doc_entry = new DocClass(iname, doc_parent());
if ($3 == iname)
cplus_open_class($3, 0, $2);
else
cplus_open_class($3, iname, $2);
if (strcmp($2,"class") == 0)
cplus_mode = CPLUS_PRIVATE;
else
cplus_mode = CPLUS_PUBLIC;
// Create a documentation entry for the class
doc_stack_top++;
doc_stack[doc_stack_top] = doc_entry;
scanner_clear_start();
nested_list = 0;
// Merge in scope from base classes
cplus_inherit_scope($4.count,$4.names);
}
} cpp_members RBRACE declaration {
if (allow) {
if ($4.names) {
if (strcmp($2,"union") != 0)
cplus_inherit($4.count, $4.names);
else {
fprintf(stderr,"%s : Line %d. Inheritance not allowed for unions.\n",input_file, line_number);
FatalError();
}
}
// Create a datatype for correctly processing the typedef
Active_typedef = new DataType();
Active_typedef->type = T_USER;
sprintf(Active_typedef->name,"%s %s", $2,$3);
Active_typedef->is_pointer = 0;
Active_typedef->implicit_ptr = 0;
// Clean up the inheritance list
if ($4.names) {
int j;
for (j = 0; j < $4.count; j++) {
if ($4.names[j]) delete [] $4.names[j];
}
delete [] $4.names;
}
if ($9.is_pointer > 0) {
fprintf(stderr,"%s : Line %d. typedef struct { } *id not supported properly. Winging it...\n", input_file, line_number);
}
// Create dump nested class code
if ($9.is_pointer > 0) {
dump_nested($3);
} else {
dump_nested($9.id);
}
// Collapse any datatypes created in the the class
cplus_register_scope(DataType::collapse_scope($3));
doc_entry = doc_stack[doc_stack_top];
if ($9.is_pointer > 0) {
cplus_class_close($3);
} else {
cplus_class_close($9.id);
}
doc_stack_top--;
doc_entry = 0;
// Create a typedef in global scope
if ($9.is_pointer == 0)
Active_typedef->typedef_add($9.id);
else {
DataType *t = new DataType(Active_typedef);
t->is_pointer += $9.is_pointer;
t->typedef_add($9.id);
cplus_register_type($9.id);
delete t;
}
cplus_mode = CPLUS_PUBLIC;
}
} typedeflist { };
/* An unnamed struct with a typedef */
| TYPEDEF cpptype LBRACE {
char *iname;
if (allow) {
init_language();
DataType::new_scope();
if ((!CPlusPlus) && (strcmp($2,"class") == 0))
fprintf(stderr,"%s : Line %d. *** WARNING ***. C++ mode is disabled (enable using -c++)\n", input_file, line_number);
iname = make_name("");
doc_entry = new DocClass(iname,doc_parent());
if (strlen(iname))
cplus_open_class("", iname, $2);
else
cplus_open_class("",0,$2);
if (strcmp($2,"class") == 0)
cplus_mode = CPLUS_PRIVATE;
else
cplus_mode = CPLUS_PUBLIC;
doc_stack_top++;
doc_stack[doc_stack_top] = doc_entry;
scanner_clear_start();
nested_list = 0;
}
} cpp_members RBRACE declaration {
if (allow) {
if ($7.is_pointer > 0) {
fprintf(stderr,"%s : Line %d. typedef %s {} *%s not supported correctly. Will be ignored.\n", input_file, line_number, $2, $7.id);
cplus_abort();
} else {
sprintf(temp_name,"CPP_CLASS:%s\n",$7.id);
if (add_symbol(temp_name, (DataType *) 0, (char *) 0)) {
fprintf(stderr,"%s : Line %d. Error. %s %s is multiply defined.\n", input_file, line_number, $2, $7.id);
FatalError();
}
}
// Create a datatype for correctly processing the typedef
Active_typedef = new DataType();
Active_typedef->type = T_USER;
sprintf(Active_typedef->name,"%s",$7.id);
Active_typedef->is_pointer = 0;
Active_typedef->implicit_ptr = 0;
// Dump nested classes
if ($7.is_pointer == 0)
dump_nested($7.id);
// Go back to previous scope
cplus_register_scope(DataType::collapse_scope((char *) 0));
doc_entry = doc_stack[doc_stack_top];
// Change name of doc_entry
doc_entry->name = copy_string($7.id);
if ($7.is_pointer == 0)
cplus_class_close($7.id);
doc_entry = 0;
doc_stack_top--;
cplus_mode = CPLUS_PUBLIC;
}
} typedeflist { }
;
cpp_other :/* A dummy class name */
extern cpptype ID SEMI {
char *iname;
if (allow) {
init_language();
iname = make_name($3);
lang->cpp_class_decl($3,iname,$2);
}
}
/* A static C++ member function (declared out of scope) */
| extern type declaration DCOLON ID LPAREN parms RPAREN SEMI {
if (allow) {
init_language();
if (!CPlusPlus)
fprintf(stderr,"%s : Line %d. *** WARNING ***. C++ mode is disabled (enable using -c++)\n", input_file, line_number);
$2->is_pointer += $3.is_pointer;
$2->is_reference = $3.is_reference;
// Fix up the function name
sprintf(temp_name,"%s::%s",$3.id,$5);
if (!Rename_true) {
Rename_true = 1;
sprintf(yy_rename,"%s_%s",$3.id,$5);
}
create_function($1, temp_name, $2, $7);
}
delete $2;
delete $7;
}
/* A static C++ member data */
| extern type declaration DCOLON ID SEMI {
if (allow) {
init_language();
if (!CPlusPlus)
fprintf(stderr,"%s : Line %d. *** WARNING ***. C++ mode is disabled (enable using -c++)\n", input_file, line_number);
$2->is_pointer += $3.is_pointer;
// Fix up the function name
sprintf(temp_name,"%s::%s",$3.id,$5);
if (!Rename_true) {
Rename_true = 1;
sprintf(yy_rename,"%s_%s",$3.id,$5);
}
create_variable($1,temp_name, $2);
}
delete $2;
}
/* Operator overloading catch */
| extern type declaration DCOLON OPERATOR {
fprintf(stderr,"%s : Line %d. Operator overloading not supported (ignored).\n", input_file, line_number);
skip_decl();
delete $2;
}
/* Template catch */
| TEMPLATE {
fprintf(stderr,"%s : Line %d. Templates not currently supported (ignored).\n",
input_file, line_number);
skip_decl();
}
/* %addmethods directive used outside of a class definition */
| ADDMETHODS ID LBRACE {
cplus_mode = CPLUS_PUBLIC;
doc_entry = cplus_set_class($2);
if (!doc_entry) {
doc_entry = new DocClass($2,doc_parent());
};
doc_stack_top++;
doc_stack[doc_stack_top] = doc_entry;
scanner_clear_start();
AddMethods = 1;
} added_members RBRACE {
cplus_unset_class();
doc_entry = 0;
doc_stack_top--;
AddMethods = 0;
}
;
added_members : cpp_member cpp_members { }
| objc_method objc_methods { }
| empty { }
;
cpp_members : cpp_member cpp_members {}
| ADDMETHODS LBRACE {
AddMethods = 1;
} cpp_members RBRACE {
AddMethods = 0;
} cpp_members { }
| error {
skip_decl();
{
static int last_error_line = -1;
if (last_error_line != line_number) {
fprintf(stderr,"%s : Line %d. Syntax error in input.\n", input_file, line_number);
FatalError();
last_error_line = line_number;
}
}
} cpp_members { }
| empty { }
;
cpp_member : type declaration LPAREN parms RPAREN cpp_end {
char *iname;
if (allow) {
init_language();
if (cplus_mode == CPLUS_PUBLIC) {
Stat_func++;
$1->is_pointer += $2.is_pointer;
$1->is_reference = $2.is_reference;
if (Verbose) {
fprintf(stderr,"Wrapping member function : %s\n",$2.id);
}
iname = make_name($2.id);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $2.id) iname = 0;
cplus_member_func($2.id, iname, $1,$4,0);
}
scanner_clear_start();
}
delete $1;
delete $4;
}
/* Virtual member function */
| VIRTUAL type declaration LPAREN parms RPAREN cpp_vend {
char *iname;
if (allow) {
init_language();
if (cplus_mode == CPLUS_PUBLIC) {
Stat_func++;
$2->is_pointer += $3.is_pointer;
$2->is_reference = $3.is_reference;
if (Verbose) {
fprintf(stderr,"Wrapping virtual member function : %s\n",$3.id);
}
iname = make_name($3.id);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $3.id) iname = 0;
cplus_member_func($3.id,iname,$2,$5,1);
}
scanner_clear_start();
}
delete $2;
delete $5;
}
/* Possibly a constructor */
| ID LPAREN parms RPAREN ctor_end {
char *iname;
if (allow) {
init_language();
if (cplus_mode == CPLUS_PUBLIC) {
Stat_func++;
if (Verbose) {
fprintf(stderr,"Wrapping C++ constructor %s\n", $1);
}
iname = make_name($1);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $1) iname = 0;
cplus_constructor($1,iname, $3);
}
scanner_clear_start();
}
delete $3;
}
/* A destructor (hopefully) */
| NOT ID LPAREN parms RPAREN cpp_end {
char *iname;
if (allow) {
init_language();
if (cplus_mode == CPLUS_PUBLIC) {
Stat_func++;
if (Verbose) {
fprintf(stderr,"Wrapping C++ destructor %s\n", $2);
}
iname = make_name($2);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $2) iname = 0;
cplus_destructor($2,iname);
}
}
scanner_clear_start();
}
/* A virtual destructor */
| VIRTUAL NOT ID LPAREN RPAREN cpp_end {
char *iname;
if (allow) {
init_language();
if (cplus_mode == CPLUS_PUBLIC) {
Stat_func++;
if (Verbose) {
fprintf(stderr,"Wrapping C++ destructor %s\n", $3);
}
iname = make_name($3);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $3) iname = 0;
cplus_destructor($3,iname);
}
}
scanner_clear_start();
}
/* Member data */
| type declaration def_args {
if (allow) {
char *iname;
init_language();
if (cplus_mode == CPLUS_PUBLIC) {
if (Active_type) delete Active_type;
Active_type = new DataType($1);
$1->is_pointer += $2.is_pointer;
$1->is_reference = $2.is_reference;
if ($1->qualifier) {
if ((strcmp($1->qualifier,"const") == 0) && ($1->is_pointer == 0)) {
// Okay. This is really some sort of C++ constant here.
if ($3.type != T_ERROR) {
iname = make_name($2.id);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $2.id) iname = 0;
cplus_declare_const($2.id,iname, $1, $3.id);
}
} else {
int oldstatus = Status;
char *tm;
if ($1->status & STAT_READONLY) {
if (!(tm = typemap_lookup("memberin",typemap_lang,$1,$2.id,"","")))
Status = Status | STAT_READONLY;
}
iname = make_name($2.id);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $2.id) iname = 0;
cplus_variable($2.id,iname,$1);
Status = oldstatus;
}
} else {
char *tm = 0;
int oldstatus = Status;
if ($1->status & STAT_READONLY) {
if (!(tm = typemap_lookup("memberin",typemap_lang,$1,$2.id,"","")))
Status = Status | STAT_READONLY;
}
iname = make_name($2.id);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $2.id) iname = 0;
cplus_variable($2.id,iname,$1);
Status = oldstatus;
if (Verbose) {
fprintf(stderr,"Wrapping member data %s\n", $2.id);
}
}
}
scanner_clear_start();
}
delete $1;
} cpp_tail { }
| type declaration array def_args {
char *iname;
if (allow) {
int oldstatus = Status;
char *tm = 0;
init_language();
if (cplus_mode == CPLUS_PUBLIC) {
if (Active_type) delete Active_type;
Active_type = new DataType($1);
$1->is_pointer += $2.is_pointer + 1;
$1->is_reference = $2.is_reference;
$1->arraystr = copy_string(ArrayString);
if (!(tm = typemap_lookup("memberin",typemap_lang,$1,$2.id,"","")))
Status = STAT_READONLY;
iname = make_name($2.id);
doc_entry = new DocDecl(iname, doc_stack[doc_stack_top]);
if (iname == $2.id) iname = 0;
cplus_variable($2.id,iname,$1);
Status = oldstatus;
if (!tm)
fprintf(stderr,"%s : Line %d. Warning. Array member will be read-only.\n",input_file,line_number);
}
scanner_clear_start();
}
delete $1;
}
/* Static Member data */
| STATIC type declaration {
char *iname;
if (allow) {
init_language();
if (cplus_mode == CPLUS_PUBLIC) {
$2->is_pointer += $3.is_pointer;
iname = make_name($3.id);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $3.id) iname = 0;
cplus_static_var($3.id,iname,$2);
if (Active_type) delete Active_type;
Active_type = new DataType($2);
if (Verbose) {
fprintf(stderr,"Wrapping static member data %s\n", $3.id);
}
}
scanner_clear_start();
}
delete $2;
} cpp_tail { }
/* Static member function */
| STATIC type declaration LPAREN parms RPAREN cpp_end {
char *iname;
if (allow) {
$2->is_pointer += $3.is_pointer;
$2->is_reference = $3.is_reference;
if (cplus_mode == CPLUS_PUBLIC) {
iname = make_name($3.id);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $3.id) iname = 0;
cplus_static_func($3.id, iname, $2, $5);
if (Verbose)
fprintf(stderr,"Wrapping static member function %s\n",$3.id);
}
scanner_clear_start();
}
delete $2;
delete $5;
}
/* Turn on public: mode */
| PUBLIC COLON {
if (allow) {
cplus_mode = CPLUS_PUBLIC;
if (Verbose)
fprintf(stderr,"Public mode\n");
scanner_clear_start();
}
}
/* Turn on private: mode */
| PRIVATE COLON {
if (allow) {
cplus_mode = CPLUS_PRIVATE;
if (Verbose)
fprintf(stderr,"Private mode\n");
scanner_clear_start();
}
}
/* Turn on protected mode */
| PROTECTED COLON {
if (allow) {
cplus_mode = CPLUS_PROTECTED;
if (Verbose)
fprintf(stderr,"Protected mode\n");
scanner_clear_start();
}
}
/* This is the new style rename */
| NAME LPAREN ID RPAREN {
if (allow) {
strcpy(yy_rename,$3);
Rename_true = 1;
}
}
/* New mode */
| NEW {
NewObject = 1;
} cpp_member {
NewObject = 0;
}
/* C++ Enum */
| ENUM ename LBRACE {scanner_clear_start();} cpp_enumlist RBRACE SEMI {
// if ename was supplied. Install it as a new integer datatype.
if (allow) {
init_language();
if (cplus_mode == CPLUS_PUBLIC) {
if ($2) {
cplus_register_type($2);
temp_type.type = T_INT;
temp_type.is_pointer = 0;
temp_type.implicit_ptr = 0;
sprintf(temp_type.name,"int");
temp_type.typedef_add($2,1);
}
}
}
}
| READONLY {
if (allow)
Status = Status | STAT_READONLY;
scanner_clear_start();
}
| READWRITE {
if (allow)
Status = Status & ~(STAT_READONLY);
scanner_clear_start();
}
/* A friend : Illegal */
| FRIEND {
if (allow)
fprintf(stderr,"%s : Line %d. Friends are not allowed--members only! (ignored)\n", input_file, line_number);
skip_decl();
scanner_clear_start();
}
/* An operator: Illegal */
| type type_extra OPERATOR {
if (allow)
fprintf(stderr,"%s : Line %d. Operator overloading not supported (ignored).\n", input_file, line_number);
skip_decl();
scanner_clear_start();
}
| cond_compile {
scanner_clear_start();
}
/* A typedef inside a class */
| typedef_decl { }
/* Pragma directive */
| cpp_pragma {
scanner_clear_start();
}
cpp_pragma : PRAGMA ID stylearg {
if (allow && (!WrapExtern)) { }
}
| PRAGMA LPAREN ID RPAREN ID stylearg {
if (allow && (!WrapExtern))
cplus_add_pragma($3,$5,$6);
}
;
/* ----------------------------------------------------------------------
Nested structure. This is a big ugly "hack". If we encounter
a nested structure, we're going to grab the text of its definition and
feed it back into the scanner. In the meantime, we need to grab
variable declaration information and generate the associated wrapper
code later. Yikes!
This really only works in a limited sense. Since we use the
code attached to the nested class to generate both C/C++ code,
it can't have any SWIG directives in it. It also needs to be parsable
by SWIG or this whole thing is going to puke.
---------------------------------------------------------------------- */
/* A struct sname { } id; declaration */
| cpptype ID LBRACE { start_line = line_number; skip_brace();
} nested_decl SEMI {
if (cplus_mode == CPLUS_PUBLIC) {
cplus_register_type($2);
if ($5.id) {
if (strcmp($1,"class") == 0) {
fprintf(stderr,"%s : Line %d. Warning. Nested classes not currently supported (ignored).\n", input_file, line_number);
/* Generate some code for a new class */
} else {
Nested *n = new Nested;
n->code << "typedef " << $1 << " "
<< CCode.get() << " $classname_" << $5.id << ";\n";
n->name = copy_string($5.id);
n->line = start_line;
n->type = new DataType;
n->type->type = T_USER;
n->type->is_pointer = $5.is_pointer;
n->type->is_reference = $5.is_reference;
n->next = 0;
add_nested(n);
}
}
}
}
/* An unnamed structure definition */
| cpptype LBRACE { start_line = line_number; skip_brace();
} declaration SEMI {
if (cplus_mode == CPLUS_PUBLIC) {
if (strcmp($1,"class") == 0) {
fprintf(stderr,"%s : Line %d. Warning. Nested classes not currently supported (ignored)\n", input_file, line_number);
/* Generate some code for a new class */
} else {
/* Generate some code for a new class */
Nested *n = new Nested;
n->code << "typedef " << $1 << " "
<< CCode.get() << " $classname_" << $4.id << ";\n";
n->name = copy_string($4.id);
n->line = start_line;
n->type = new DataType;
n->type->type = T_USER;
n->type->is_pointer = $4.is_pointer;
n->type->is_reference = $4.is_reference;
n->next = 0;
add_nested(n);
}
}
}
/* An empty class declaration */
| cpptype ID SEMI {
if (cplus_mode == CPLUS_PUBLIC) {
cplus_register_type($2);
}
}
/* Other miscellaneous errors */
| type stars LPAREN {
skip_decl();
fprintf(stderr,"%s : Line %d. Function pointers not currently supported (ignored).\n", input_file, line_number);
}
| strict_type LPAREN STAR {
skip_decl();
fprintf(stderr,"%s : Line %d. Function pointers not currently supported (ignored).\n", input_file, line_number);
}
| ID LPAREN STAR {
skip_decl();
fprintf(stderr,"%s : Line %d. Function pointers not currently supported (ignored).\n", input_file, line_number);
}
| doc_enable { }
| SEMI { }
;
nested_decl : declaration { $$ = $1;}
| empty { $$.id = 0; }
;
type_extra : stars {}
| AND {}
| empty {}
;
cpp_tail : SEMI { }
| COMMA declaration def_args {
if (allow) {
int oldstatus = Status;
char *tm;
init_language();
if (cplus_mode == CPLUS_PUBLIC) {
temp_typeptr = new DataType(Active_type);
temp_typeptr->is_pointer += $2.is_pointer;
if (Verbose) {
fprintf(stderr,"Wrapping member variable : %s\n",$2.id);
}
Stat_var++;
doc_entry = new DocDecl($2.id,doc_stack[doc_stack_top]);
if (temp_typeptr->status & STAT_READONLY) {
if (!(tm = typemap_lookup("memberin",typemap_lang,temp_typeptr,$2.id,"","")))
Status = Status | STAT_READONLY;
}
cplus_variable($2.id,(char *) 0,temp_typeptr);
Status = oldstatus;
delete temp_typeptr;
}
scanner_clear_start();
}
} cpp_tail { }
| COMMA declaration array def_args {
if (allow) {
int oldstatus = Status;
char *tm;
init_language();
if (cplus_mode == CPLUS_PUBLIC) {
temp_typeptr = new DataType(Active_type);
temp_typeptr->is_pointer += $2.is_pointer;
if (Verbose) {
fprintf(stderr,"Wrapping member variable : %s\n",$2.id);
}
Stat_var++;
if (!(tm = typemap_lookup("memberin",typemap_lang,temp_typeptr,$2.id,"","")))
Status = Status | STAT_READONLY;
doc_entry = new DocDecl($2.id,doc_stack[doc_stack_top]);
if (temp_typeptr->status & STAT_READONLY) Status = Status | STAT_READONLY;
cplus_variable($2.id,(char *) 0,temp_typeptr);
Status = oldstatus;
if (!tm)
fprintf(stderr,"%s : Line %d. Warning. Array member will be read-only.\n",input_file,line_number);
delete temp_typeptr;
}
scanner_clear_start();
}
} cpp_tail { }
;
cpp_end : cpp_const SEMI {
CCode = "";
}
| cpp_const LBRACE { skip_brace(); }
;
cpp_vend : cpp_const SEMI { CCode = ""; }
| cpp_const EQUAL definetype SEMI { CCode = ""; }
| cpp_const LBRACE { skip_brace(); }
;
cpp_enumlist : cpp_enumlist COMMA cpp_edecl {}
| cpp_edecl {}
;
cpp_edecl : ID {
if (allow) {
if (cplus_mode == CPLUS_PUBLIC) {
if (Verbose) {
fprintf(stderr,"Creating enum value %s\n", $1);
}
Stat_const++;
temp_typeptr = new DataType(T_INT);
doc_entry = new DocDecl($1,doc_stack[doc_stack_top]);
cplus_declare_const($1, (char *) 0, temp_typeptr, (char *) 0);
delete temp_typeptr;
scanner_clear_start();
}
}
}
| ID EQUAL etype {
if (allow) {
if (cplus_mode == CPLUS_PUBLIC) {
if (Verbose) {
fprintf(stderr, "Creating enum value %s = %s\n", $1, $3.id);
}
Stat_const++;
temp_typeptr = new DataType(T_INT);
doc_entry = new DocDecl($1,doc_stack[doc_stack_top]);
cplus_declare_const($1,(char *) 0, temp_typeptr,(char *) 0);
// OLD : Bug with value cplus_declare_const($1,(char *) 0, temp_typeptr,$3.id);
delete temp_typeptr;
scanner_clear_start();
}
}
}
| NAME LPAREN ID RPAREN ID {
if (allow) {
if (cplus_mode == CPLUS_PUBLIC) {
if (Verbose) {
fprintf(stderr,"Creating enum value %s\n", $5);
}
Stat_const++;
temp_typeptr = new DataType(T_INT);
doc_entry = new DocDecl($3,doc_stack[doc_stack_top]);
cplus_declare_const($5, $3, temp_typeptr, (char *) 0);
delete temp_typeptr;
scanner_clear_start();
}
}
}
| NAME LPAREN ID RPAREN ID EQUAL etype {
if (allow) {
if (cplus_mode == CPLUS_PUBLIC) {
if (Verbose) {
fprintf(stderr, "Creating enum value %s = %s\n", $5, $7.id);
}
Stat_const++;
temp_typeptr = new DataType(T_INT);
doc_entry = new DocDecl($3,doc_stack[doc_stack_top]);
cplus_declare_const($5,$3, temp_typeptr, (char *) 0);
// Old : bug with value cplus_declare_const($5,$3, temp_typeptr,$7.id);
delete temp_typeptr;
scanner_clear_start();
}
}
}
| cond_compile cpp_edecl { }
| empty { }
;
inherit : COLON base_list {
$$ = $2;
}
| empty {
$$.names = (char **) 0;
$$.count = 0;
}
;
base_list : base_specifier {
int i;
$$.names = new char *[NI_NAMES];
$$.count = 0;
for (i = 0; i < NI_NAMES; i++){
$$.names[i] = (char *) 0;
}
if ($1) {
$$.names[$$.count] = copy_string($1);
$$.count++;
}
}
| base_list COMMA base_specifier {
$$ = $1;
if ($3) {
$$.names[$$.count] = copy_string($3);
$$.count++;
}
}
;
base_specifier : ID {
fprintf(stderr,"%s : Line %d. No access specifier given for base class %s (ignored).\n",
input_file,line_number,$1);
$$ = (char *) 0;
}
| VIRTUAL ID {
fprintf(stderr,"%s : Line %d. No access specifier given for base class %s (ignored).\n",
input_file,line_number,$2);
$$ = (char *) 0;
}
| VIRTUAL access_specifier ID {
if (strcmp($2,"public") == 0) {
$$ = $3;
} else {
fprintf(stderr,"%s : Line %d. %s inheritance not supported (ignored).\n",
input_file,line_number,$2);
$$ = (char *) 0;
}
}
| access_specifier ID {
if (strcmp($1,"public") == 0) {
$$ = $2;
} else {
fprintf(stderr,"%s : Line %d. %s inheritance not supported (ignored).\n",
input_file,line_number,$1);
$$ = (char *) 0;
}
}
| access_specifier VIRTUAL ID {
if (strcmp($1,"public") == 0) {
$$ = $3;
} else {
fprintf(stderr,"%s : Line %d. %s inheritance not supported (ignored).\n",
input_file,line_number,$1);
$$ = (char *) 0;
}
}
;
access_specifier : PUBLIC { $$ = "public"; }
| PRIVATE { $$ = "private"; }
| PROTECTED { $$ = "protected"; }
;
cpptype : CLASS { $$ = "class"; }
| STRUCT { $$ = "struct"; }
| UNION {$$ = "union"; }
;
cpp_const : CONST {}
| THROW LPAREN parms RPAREN { delete $3;}
| empty {}
;
/* Constructor initializer */
ctor_end : cpp_const ctor_initializer SEMI {
CCode = "";
}
| cpp_const ctor_initializer LBRACE { skip_brace(); }
;
ctor_initializer : COLON mem_initializer_list {}
| empty {}
;
mem_initializer_list : mem_initializer { }
| mem_initializer_list COMMA mem_initializer { }
;
mem_initializer : ID LPAREN expr_list RPAREN { }
| ID LPAREN RPAREN { }
;
expr_list : expr { }
| expr_list COMMA expr { }
;
/**************************************************************/
/* Objective-C parsing */
/**************************************************************/
objective_c : OC_INTERFACE ID objc_inherit {
ObjCClass = 1;
init_language();
cplus_mode = CPLUS_PROTECTED;
sprintf(temp_name,"CPP_CLASS:%s\n",$2);
if (add_symbol(temp_name,(DataType *) 0, (char *) 0)) {
fprintf(stderr,"%s : Line %d. @interface %s is multiple defined.\n",
input_file,line_number,$2);
FatalError();
}
// Create a new documentation entry
doc_entry = new DocClass($2,doc_parent());
doc_stack_top++;
doc_stack[doc_stack_top] = doc_entry;
scanner_clear_start();
cplus_open_class($2, (char *) 0, ""); // Open up a new C++ class
} LBRACE objc_data RBRACE objc_methods OC_END {
if ($3) {
char *inames[1];
inames[0] = $3;
cplus_inherit(1,inames);
}
// Restore original doc entry for this class
doc_entry = doc_stack[doc_stack_top];
cplus_class_close($2);
doc_entry = 0;
doc_stack_top--;
cplus_mode = CPLUS_PUBLIC;
ObjCClass = 0;
delete $2;
delete $3;
}
/* An obj-c category declaration */
| OC_INTERFACE ID LPAREN ID RPAREN objc_protolist {
ObjCClass = 1;
init_language();
cplus_mode = CPLUS_PROTECTED;
doc_entry = cplus_set_class($2);
if (!doc_entry) {
doc_entry = new DocClass($2,doc_parent());
}
doc_stack_top++;
doc_stack[doc_stack_top] = doc_entry;
scanner_clear_start();
} objc_methods OC_END {
cplus_unset_class();
doc_entry = 0;
doc_stack_top--;
}
| OC_IMPLEMENT { skip_to_end(); }
| OC_PROTOCOL { skip_to_end(); }
| OC_CLASS ID initlist SEMI {
char *iname = make_name($2);
init_language();
lang->cpp_class_decl($2,iname,"");
for (int i = 0; i <$3.count; i++) {
if ($3.names[i]) {
iname = make_name($3.names[i]);
lang->cpp_class_decl($3.names[i],iname,"");
delete [] $3.names[i];
}
}
delete [] $3.names;
}
;
objc_inherit : COLON ID objc_protolist { $$ = $2;}
| objc_protolist empty { $$ = 0; }
;
objc_protolist : LESSTHAN { skip_template();
CCode.strip(); // Strip whitespace
CCode.replace("<","< ");
CCode.replace(">"," >");
$$ = CCode.get();
}
| empty {
$$ = "";
}
;
objc_data : objc_vars objc_data { }
| OC_PUBLIC {
cplus_mode = CPLUS_PUBLIC;
} objc_data { }
| OC_PRIVATE {
cplus_mode = CPLUS_PRIVATE;
} objc_data { }
| OC_PROTECTED {
cplus_mode = CPLUS_PROTECTED;
} objc_data { }
| error {
if (!Error) {
skip_decl();
{
static int last_error_line = -1;
if (last_error_line != line_number) {
fprintf(stderr,"%s : Line %d. Syntax error in input.\n", input_file, line_number);
FatalError();
last_error_line = line_number;
}
Error = 1;
}
}
} objc_data { }
| empty { }
;
objc_vars : objc_var objc_vartail SEMI {
}
;
/* An objective-C member variable */
objc_var : type declaration {
if (cplus_mode == CPLUS_PUBLIC) {
int oldstatus = Status;
char *tm;
char *iname;
if (Active_type) delete Active_type;
Active_type = new DataType($1);
$1->is_pointer += $2.is_pointer;
$1->is_reference = $2.is_reference;
if ($1->status & STAT_READONLY) {
if (!(tm = typemap_lookup("memberin",typemap_lang,$1,$2.id,"","")))
Status = Status | STAT_READONLY;
}
iname = make_name($2.id);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $2.id) iname = 0;
cplus_variable($2.id,iname,$1);
Status = oldstatus;
}
scanner_clear_start();
delete $1;
}
| type declaration array {
if (cplus_mode == CPLUS_PUBLIC) {
int oldstatus = Status;
char *tm, *iname;
if (Active_type) delete Active_type;
Active_type = new DataType($1);
$1->is_pointer += $2.is_pointer;
$1->is_reference = $2.is_reference;
$1->arraystr = copy_string(ArrayString);
if ($1->status & STAT_READONLY) {
if (!(tm = typemap_lookup("memberin",typemap_lang,$1,$2.id,"","")))
Status = Status | STAT_READONLY;
}
iname = make_name($2.id);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $2.id) iname = 0;
cplus_variable($2.id,iname,$1);
Status = oldstatus;
}
scanner_clear_start();
delete $1;
}
| NAME LPAREN ID RPAREN {
strcpy(yy_rename,$3);
Rename_true = 1;
} objc_var { };
objc_vartail : COMMA declaration objc_vartail {
if (cplus_mode == CPLUS_PUBLIC) {
int oldstatus = Status;
char *tm, *iname;
DataType *t = new DataType (Active_type);
t->is_pointer += $2.is_pointer;
t->is_reference = $2.is_reference;
if (t->status & STAT_READONLY) {
if (!(tm = typemap_lookup("memberin",typemap_lang,t,$2.id,"","")))
Status = Status | STAT_READONLY;
}
iname = make_name($2.id);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $2.id) iname = 0;
cplus_variable($2.id,iname,t);
Status = oldstatus;
delete t;
}
scanner_clear_start();
}
| COMMA declaration array objc_vartail {
char *iname;
if (cplus_mode == CPLUS_PUBLIC) {
int oldstatus = Status;
char *tm;
DataType *t = new DataType (Active_type);
t->is_pointer += $2.is_pointer;
t->is_reference = $2.is_reference;
t->arraystr = copy_string(ArrayString);
if (t->status & STAT_READONLY) {
if (!(tm = typemap_lookup("memberin",typemap_lang,t,$2.id,"","")))
Status = Status | STAT_READONLY;
}
iname = make_name($2.id);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $2.id) iname = 0;
cplus_variable($2.id,iname,t);
Status = oldstatus;
delete t;
}
scanner_clear_start();
}
| empty { }
;
objc_methods : objc_method objc_methods { };
| ADDMETHODS LBRACE {
AddMethods = 1;
} objc_methods RBRACE {
AddMethods = 0;
}
| NAME LPAREN ID RPAREN {
strcpy(yy_rename,$3);
Rename_true = 1;
} objc_methods { }
| error {
skip_decl();
if (!Error) {
{
static int last_error_line = -1;
if (last_error_line != line_number) {
fprintf(stderr,"%s : Line %d. Syntax error in input.\n", input_file, line_number);
FatalError();
last_error_line = line_number;
}
Error = 1;
}
}
} objc_methods { }
| empty { }
;
objc_method : MINUS objc_ret_type ID objc_args objc_end {
char *iname;
// An objective-C instance function
// This is like a C++ member function
if (strcmp($3,objc_destruct) == 0) {
// This is an objective C destructor
doc_entry = new DocDecl($3,doc_stack[doc_stack_top]);
cplus_destructor($3,(char *) 0);
} else {
iname = make_name($3);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $3) iname = 0;
cplus_member_func($3,iname,$2,$4,0);
scanner_clear_start();
delete $2;
delete $3;
delete $4;
}
}
| PLUS objc_ret_type ID objc_args objc_end {
char *iname;
// An objective-C class function
// This is like a c++ static member function
if (strcmp($3,objc_construct) == 0) {
// This is an objective C constructor
doc_entry = new DocDecl($3,doc_stack[doc_stack_top]);
cplus_constructor($3,0,$4);
} else {
iname = make_name($3);
doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]);
if (iname == $3) iname = 0;
cplus_static_func($3,iname,$2,$4);
}
scanner_clear_start();
delete $2;
delete $3;
delete $4;
}
;
objc_end : SEMI { CCode = ""; }
| LBRACE { skip_brace(); }
;
objc_ret_type : LPAREN type RPAREN {
$$ = $2;
}
| LPAREN type stars RPAREN {
$$ = $2;
$$->is_pointer += $3;
}
| empty { /* Empty type means "id" type */
$$ = new DataType(T_VOID);
sprintf($$->name,"id");
$$->is_pointer = 1;
$$->implicit_ptr = 1;
}
;
objc_arg_type : LPAREN parm RPAREN {
$$ = new DataType($2->t);
delete $2;
}
| empty {
$$ = new DataType(T_VOID);
sprintf($$->name,"id");
$$->is_pointer = 1;
$$->implicit_ptr = 1;
}
;
objc_args : objc_args objc_separator objc_arg_type ID {
Parm *p= new Parm($3,$4);
p->objc_separator = $2;
$$ = $1;
$$->append(p);
}
| empty {
$$ = new ParmList;
}
;
objc_separator : COLON { $$ = copy_string(":"); }
| ID COLON { $$ = new char[strlen($1)+2];
strcpy($$,$1);
strcat($$,":");
delete $1;
}
;
/* Miscellaneous stuff */
/* Documentation style list */
stylelist : ID stylearg styletail {
$$ = $3;
$$.names[$$.count] = copy_string($1);
$$.values[$$.count] = copy_string($2);
format_string($$.values[$$.count]);
$$.count++;
}
;
styletail : styletail COMMA ID stylearg {
$$ = $1;
$$.names[$$.count] = copy_string($3);
$$.values[$$.count] = copy_string($4);
format_string($$.values[$$.count]);
$$.count++;
}
| empty {
$$.names = new char *[NI_NAMES];
$$.values = new char *[NI_NAMES];
$$.count = 0;
}
;
stylearg : EQUAL NUM_INT {
$$ = $2;
}
| EQUAL STRING {
$$ = $2;
}
| empty {
$$ = 0;
}
;
/* --------------------------------------------------------------
* Type-map parameters
* -------------------------------------------------------------- */
tm_method : ID {
$$ = $1;
}
| CONST {
$$ = copy_string("const");
}
;
tm_list : typemap_parm tm_tail {
$$ = $1;
$$->next = $2;
}
;
tm_tail : COMMA typemap_parm tm_tail {
$$ = $2;
$$->next = $3;
}
| empty { $$ = 0;}
;
typemap_parm : type typemap_name {
if (InArray) {
$1->is_pointer++;
$1->arraystr = copy_string(ArrayString);
}
$$ = new TMParm;
$$->p = new Parm($1,$2);
$$->p->call_type = 0;
$$->args = tm_parm;
delete $1;
delete $2;
}
| type stars typemap_name {
$$ = new TMParm;
$$->p = new Parm($1,$3);
$$->p->t->is_pointer += $2;
$$->p->call_type = 0;
if (InArray) {
$$->p->t->is_pointer++;
$$->p->t->arraystr = copy_string(ArrayString);
}
$$->args = tm_parm;
delete $1;
delete $3;
}
| type AND typemap_name {
$$ = new TMParm;
$$->p = new Parm($1,$3);
$$->p->t->is_reference = 1;
$$->p->call_type = 0;
$$->p->t->is_pointer++;
if (!CPlusPlus) {
fprintf(stderr,"%s : Line %d. Warning. Use of C++ Reference detected. Use the -c++ option.\n", input_file, line_number);
}
$$->args = tm_parm;
delete $1;
delete $3;
}
| type LPAREN stars typemap_name RPAREN LPAREN parms RPAREN {
fprintf(stderr,"%s : Line %d. Error. Function pointer not allowed (remap with typedef).\n", input_file, line_number);
FatalError();
$$ = new TMParm;
$$->p = new Parm($1,$4);
$$->p->t->type = T_ERROR;
$$->p->name = copy_string($4);
strcpy($$->p->t->name,"<function ptr>");
$$->args = tm_parm;
delete $1;
delete $4;
delete $7;
}
;
typemap_name : ID typemap_args {
$$ = $1;
InArray = 0;
}
| ID array {
ArrayBackup = "";
ArrayBackup << ArrayString;
} typemap_args {
$$ = $1;
InArray = $2;
ArrayString = "";
ArrayString << ArrayBackup;
}
| array {
ArrayBackup = "";
ArrayBackup << ArrayString;
} typemap_args {
$$ = new char[1];
$$[0] = 0;
InArray = $1;
ArrayString = "";
ArrayString << ArrayBackup;
}
| typemap_args { $$ = new char[1];
$$[0] = 0;
InArray = 0;
}
;
typemap_args : LPAREN parms RPAREN {
tm_parm = $2;
}
| empty {
tm_parm = 0;
}
;
idstring : ID {$$ = $1;}
| STRING { $$ = $1;}
;
/* User defined directive */
user_directive : USERDIRECTIVE LPAREN parms RPAREN uservalue { }
| USERDIRECTIVE uservalue { }
;
uservalue : ID SEMI { }
| STRING SEMI { }
| LBRACE RBRACE { }
;
/* Parsing of expressions, but only for throw away code */
/* Might need someday
dummyexpr : NUM_INT { }
| NUM_FLOAT { }
| NUM_UNSIGNED { }
| NUM_LONG { }
| NUM_ULONG { }
| SIZEOF LPAREN type RPAREN { }
| ID { }
| dummyexpr PLUS dummyexpr { }
| dummyexpr MINUS dummyexpr { }
| dummyexpr STAR dummyexpr { }
| dummyexpr SLASH dummyexpr { }
| dummyexpr AND dummyexpr { }
| dummyexpr OR dummyexpr { }
| dummyexpr XOR dummyexpr { }
| dummyexpr LSHIFT dummyexpr { }
| dummyexpr RSHIFT dummyexpr { }
| MINUS dummyexpr %prec UMINUS { }
| NOT dummyexpr { }
| LPAREN dummyexpr RPAREN { }
;
*/
empty : ;
%%
void error_recover() {
int c;
c = yylex();
while ((c > 0) && (c != SEMI))
c = yylex();
}
/* Called by the parser (yyparse) when an error is found.*/
void yyerror (char *) {
// Fprintf(stderr,"%s : Line %d. Syntax error.\n", input_file, line_number);
// error_recover();
}