swig/Source/LParse/parser.y
Dave Beazley 76c442982f Work in progress
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@525 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2000-07-06 21:23:29 +00:00

1913 lines
53 KiB
Text

%{
/* -----------------------------------------------------------------------------
* parser.y
*
* YACC grammar for Dave's lame C parser. Based loosely on the SWIG1.1 parser
*
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
*
* Copyright (C) 1999-2000. The University of Chicago
* See the file LICENSE for information on usage and redistribution.
* ----------------------------------------------------------------------------- */
/* These defines are to move the bison generated functions into their own namespace */
#define yylex lparse_yylex
#define yyerror lparse_yyerror
#define yyparse lparse_yyparse
#define yylval lparse_yylval
#define yychar lparse_yychar
#define yynerrs lparse_yynerrs
static char cvsroot[] = "$Header$";
extern int lparse_yylex();
extern void LParse_strict_type(int);
void yyerror (char *s);
#include "lparse.h"
#include "preprocessor.h"
static DOH *top = 0;
/* Pre-created attribute name objects. Used to improve parsing performance */
static DOH *ATTR_TAG = 0;
static DOH *ATTR_CHILD = 0;
static DOH *ATTR_PARENT = 0;
static DOH *ATTR_NEXT = 0;
static DOH *ATTR_PREV = 0;
static DOH *ATTR_NAME = 0;
static DOH *ATTR_VALUE = 0;
static DOH *ATTR_TYPE = 0;
static DOH *ATTR_PARMS = 0;
static DOH *ATTR_PARM = 0;
static DOH *ATTR_STORAGE = 0;
static DOH *TAG_ENUMVALUE = 0;
static DOH *TAG_FUNCTION = 0;
static DOH *TAG_VARIABLE = 0;
/* Set parent node of a collection of children */
static void setparent(DOH *parent, DOH *child) {
DOH *o;
o = child;
while (o) {
Setattr(o,ATTR_PARENT,parent);
o = Getattr(o,ATTR_NEXT);
}
}
/* Create all back links so we get a doubly-linked lists */
static void create_backlinks(DOH *top) {
DOH *prev = 0;
DOH *obj;
if (!top) return;
obj = top;
while (obj) {
if (prev) {
Setattr(obj,ATTR_PREV,prev);
}
create_backlinks(Getattr(obj,ATTR_CHILD));
prev = obj;
obj = Getattr(obj,ATTR_NEXT);
}
}
/* LParse_parse() - Main entry point to the C parser */
DOH *LParse_parse(DOH *str) {
int yyparse();
DOH *tp;
if (!ATTR_NEXT) {
ATTR_PARENT = NewString("parent");
DohIntern(ATTR_PARENT);
ATTR_NEXT = NewString("next");
DohIntern(ATTR_NEXT);
ATTR_PREV = NewString("prev");
DohIntern(ATTR_PREV);
ATTR_CHILD = NewString("child");
DohIntern(ATTR_CHILD);
ATTR_TAG = NewString("tag");
DohIntern(ATTR_TAG);
ATTR_NAME = NewString("name");
DohIntern(ATTR_NAME);
ATTR_VALUE = NewString("value");
DohIntern(ATTR_VALUE);
ATTR_TYPE = NewString("type");
DohIntern(ATTR_TYPE);
ATTR_PARMS = NewString("parms");
DohIntern(ATTR_PARMS);
ATTR_PARM = NewString("parm");
DohIntern(ATTR_PARM);
ATTR_STORAGE = NewString("storage");
DohIntern(ATTR_STORAGE);
TAG_ENUMVALUE = NewString("enumvalue");
DohIntern(TAG_ENUMVALUE);
TAG_FUNCTION = NewString("function");
DohIntern(TAG_FUNCTION);
TAG_VARIABLE = NewString("variable");
DohIntern(TAG_VARIABLE);
}
LParse_push(str);
top = 0;
tp = NewHash();
Setattr(tp, "tag", "includefile");
Setattr(tp, ATTR_NAME, Getfile(str));
yyparse();
Setattr(tp, ATTR_CHILD, top);
setparent(tp,top);
create_backlinks(tp);
return tp;
}
static DOH *new_node(char *tag, DOH *file, int line) {
DOH *o;
o = NewHash();
Setattr(o,ATTR_TAG,tag);
Setline(o,line);
Setfile(o,file);
return o;
}
/* Take a parameter list and produce a type object */
static DOH *parmstotype(DOH *parms) {
int i, l;
DOH *p, *r;
DOHList *ty;
ty = NewList();
p = parms;
while (p) {
Append(ty,Getattr(p,ATTR_TYPE));
p = Getattr(p,ATTR_NEXT);
}
r = NewString("");
SwigType_add_function(r,ty);
Delete(ty);
return r;
}
#ifdef NEED_ALLOC
void *alloca(unsigned n) {
return((void *) malloc(n));
}
#else
/* This redefinition is apparently needed on a number of machines */
#undef alloca
#define alloca malloc
#endif
/* Promote the type of arithmetic expressions */
static int promote(int t1, int t2) {
if ((t1 == LPARSE_T_ERROR) || (t2 == LPARSE_T_ERROR)) return LPARSE_T_ERROR;
if ((t1 == LPARSE_T_DOUBLE) || (t2 == LPARSE_T_DOUBLE)) return LPARSE_T_DOUBLE;
if ((t1 == LPARSE_T_FLOAT) || (t2 == LPARSE_T_FLOAT)) return LPARSE_T_FLOAT;
if ((t1 == LPARSE_T_ULONG) || (t2 == LPARSE_T_ULONG)) return LPARSE_T_ULONG;
if ((t1 == LPARSE_T_LONG) || (t2 == LPARSE_T_LONG)) return LPARSE_T_LONG;
if ((t1 == LPARSE_T_UINT) || (t2 == LPARSE_T_UINT)) return LPARSE_T_UINT;
if ((t1 == LPARSE_T_INT) || (t2 == LPARSE_T_INT)) return LPARSE_T_INT;
if ((t1 == LPARSE_T_USHORT) || (t2 == LPARSE_T_USHORT)) return LPARSE_T_SHORT;
if ((t1 == LPARSE_T_SHORT) || (t2 == LPARSE_T_SHORT)) return LPARSE_T_SHORT;
if ((t1 == LPARSE_T_UCHAR) || (t2 == LPARSE_T_UCHAR)) return LPARSE_T_UCHAR;
if ((t1 == LPARSE_T_CHAR) || (t2 == LPARSE_T_CHAR)) return LPARSE_T_INT;
if (t1 != t2) {
LParse_error(0,0,"Type mismatch in constant expression.\n");
}
return t1;
}
%}
%union {
struct {
DOH *filename;
int line;
DOH *text;
int ivalue;
void *data;
} tok;
DOH *node;
struct {
DOH *node;
DOH *last;
} nodelist;
struct {
DOH *id;
DOH *decl;
} decl;
struct {
DOH *name;
DOH *value;
DOH *array;
} pname;
struct {
DOH *name;
DOH *array;
DOH *parms;
} tmname;
};
/* Literals */
%token <tok> ID TYPE_TYPEDEF
%token <tok> HBLOCK
%token <tok> STRING
%token <tok> NUM_INT NUM_FLOAT CHARCONST NUM_UNSIGNED NUM_LONG NUM_ULONG
/* C Symbols */
%token <tok> LPAREN RPAREN LBRACE RBRACE COMMA SEMI PERIOD LBRACKET RBRACKET EQUAL COLON POUND
/* C keywords */
%token <tok> CONST DEFINED ENUM EXTERN SIZEOF STATIC STRUCT TYPEDEF UNION
/* C++ keywords */
%token <tok> CLASS FRIEND OPERATOR PRIVATE PROTECTED PUBLIC TEMPLATE THROW
/* Objective C keywords */
%token <tok> OC_INTERFACE OC_END OC_PUBLIC OC_PRIVATE OC_PROTECTED OC_CLASS OC_IMPLEMENT OC_PROTOCOL
/* C Types */
%token <tok> TYPE_INT TYPE_UNSIGNED TYPE_SHORT TYPE_LONG TYPE_FLOAT TYPE_DOUBLE TYPE_CHAR TYPE_VOID TYPE_SIGNED TYPE_BOOL
/* SWIG directives */
%token <tok> ADDMETHODS ALPHA_MODE APPLY CHECKOUT CLEAR CONSTANT DOCONLY DOC_DISABLE DOC_ENABLE ECHO EXCEPT
%token <tok> ILLEGAL IMPORT INCLUDE INIT INLINE LOCALSTYLE MACRO MODULE NAME NATIVE NEW PRAGMA
%token <tok> RAW_MODE READONLY READWRITE RENAME RUNTIME SECTION STYLE SUBSECTION SUBSUBSECTION TEXT TITLE
%token <tok> TYPE TYPEMAP USERDIRECTIVE WEXTERN WRAPPER MAP
/* Operators */
%left <tok> LOR
%left <tok> LAND
%left <tok> EQUALTO NOTEQUAL GREATERTHAN LESSTHAN LTEQUAL GTEQUAL
%left <tok> OR
%left <tok> XOR
%left <tok> AND
%left <tok> LSHIFT RSHIFT
%left <tok> PLUS MINUS
%left <tok> STAR SLASH
%left <tok> UMINUS NOT LNOT
%left <tok> DCOLON
%type <tok> idstring template_decl cpptype expr definetype def_args storage_spec pragma_arg ename
%type <node> file_include_type parm parms ptail idlist stylelist styletail stars
%type <node> array array2
%type <node> type strict_type opt_signed opt_unsigned
%type <decl> declaration
%type <pname> pname
%type <node> tm_args tm_parm tm_tail tm_list
%type <tmname> tm_name
%type <tok> tm_method
%type <node> statement swig_directive c_declaration
%type <node> file_include code_block doc_directive except_directive pragma_directive modifier_directive native_directive typemap_directive map_directive
%type <node> variable_decl function_decl enum_decl typedef_decl stail edecl typedeflist map_element
%type <nodelist> enumlist interface
%type <node> inherit base_list
%type <tok> base_specifier access_specifier cpp_end ctor_end opt_id
%type <node> cpp_decl cpp_class cpp_other
%%
/* The productions of the grammar with their
associated semantic actions. */
program : interface {
top = $1.node;
}
;
interface : interface statement {
DOH *o, *o2;
if (!$1.node) {
$$.node = $2;
o = $2;
while (o) {
o2 = o;
o = Getattr(o,ATTR_NEXT);
}
$$.last = o2;
} else {
if ($2) {
o = $1.last;
if (o) {
Setattr(o,ATTR_NEXT,$2);
} else {
Setattr($1.node,ATTR_NEXT,$2);
}
o = $2;
while (o) {
o2 = o;
o = Getattr(o,ATTR_NEXT);
}
$1.last = o2;
}
$$ = $1;
}
}
| empty { $$.node = 0; $$.last = 0; }
;
statement : swig_directive { $$ = $1; }
| c_declaration { $$ = $1; }
| LBRACE interface RBRACE {
$$ = new_node("scope",$1.filename,$1.line);
if ($2.node) {
Setattr($$,ATTR_CHILD,$2.node);
setparent($$,$2.node);
}
}
| SEMI { $$ = 0; }
| error { $$ = 0; }
;
/* =============================================================================
* -- SWIG DIRECTIVES --
* ============================================================================= */
swig_directive : MODULE idstring {
$$ = new_node("moduledirective",$1.filename,$1.line);
Setattr($$,ATTR_NAME,$2.text);
}
| MACRO ID COMMA STRING COMMA NUM_INT LBRACE {
LParse_macro_location($2.text,$1.filename,$1.line);
LParse_set_location($4.text, atoi(Char($6.text))-1);
} interface RBRACE {
LParse_macro_location(0,0,0);
LParse_set_location($7.filename,$7.line-1);
$$ = $9.node;
}
| RENAME ID ID SEMI {
$$ = new_node("renamedirective",$2.filename,$2.line);
Setattr($$,"oldname",$2.text);
Setattr($$,"newname",$3.text);
}
| CONSTANT ID definetype SEMI {
$$ = new_node("constant",$2.filename, $2.line);
Setattr($$,ATTR_NAME,$2.text);
Setattr($$,ATTR_VALUE,$3.text);
switch($3.ivalue) {
case LPARSE_T_DOUBLE:
Setattr($$,ATTR_TYPE,"double");
break;
case LPARSE_T_FLOAT:
Setattr($$,ATTR_TYPE,"float");
break;
case LPARSE_T_ULONG:
Setattr($$,ATTR_TYPE,"unsigned long");
break;
case LPARSE_T_LONG:
Setattr($$,ATTR_TYPE,"long");
break;
case LPARSE_T_UINT:
Setattr($$,ATTR_TYPE,"unsigned int");
break;
case LPARSE_T_INT:
Setattr($$,ATTR_TYPE,"int");
break;
case LPARSE_T_USHORT:
Setattr($$,ATTR_TYPE,"unsigned short");
break;
case LPARSE_T_SHORT:
Setattr($$,ATTR_TYPE,"short");
break;
case LPARSE_T_UCHAR:
Setattr($$,ATTR_TYPE,"unsigned char");
break;
case LPARSE_T_CHAR:
Setattr($$,ATTR_TYPE,"char");
break;
case LPARSE_T_STRING:
Setattr($$,ATTR_TYPE,"*.char");
break;
default:
break;
}
}
| echo_directive { $$ = 0; }
| file_include { $$ = $1; }
| code_block { $$ = $1; }
| doc_directive { $$ = $1; }
| except_directive { $$ = $1; }
| pragma_directive { $$ = $1; }
| modifier_directive { $$ = $1; }
| native_directive { $$ = $1; }
| typemap_directive { $$ = $1; }
| map_directive { $$ = $1; }
| TYPE ID idlist SEMI { $$ = 0; }
;
echo_directive: ECHO HBLOCK { Printf(stderr,"%s\n", $2.text); }
| ECHO STRING { Printf(stderr,"%s\n", $2.text); }
;
/* -- File inclusion directives -- */
file_include : file_include_type STRING LBRACE {
Setattr($1,ATTR_NAME,$2.text);
$$ = $1;
LParse_set_location($2.text,0);
} interface RBRACE {
LParse_set_location($3.filename,$3.line + 1);
if ($5.node) {
Setattr($$,ATTR_CHILD,$5.node);
setparent($$,$5.node);
}
}
file_include_type : INCLUDE { $$ = new_node("includefile",$1.filename,$1.line); }
| WEXTERN { $$ = new_node("externfile",$1.filename,$1.line); }
| IMPORT { $$ = new_node("importfile", $1.filename,$1.line); }
;
/* -- Modifier directives -- */
modifier_directive : READONLY { $$ = new_node("readonlydirective",$1.filename, $1.line); }
| READWRITE { $$ = new_node("readwritedirective",$1.filename,$1.line); }
| NAME LPAREN idstring RPAREN {
$$ = new_node("namedirective",$3.filename,$3.line);
Setattr($$,ATTR_NAME,$3.text);
}
| NEW {
$$ = new_node("newdirective",$1.filename,$1.line);
}
;
/* -- Code inclusion directives -- */
code_block : HBLOCK {
$$ = new_node("headerblock",$1.filename,$1.line);
Setattr($$,"code", $1.text);
}
| WRAPPER HBLOCK {
$$ = new_node("wrapperblock",$2.filename,$2.line);
Setattr($$,"code",$2.text);
}
| INIT HBLOCK {
$$ = new_node("initblock",$2.filename,$2.line);
Setattr($$,"code",$2.text);
}
| INLINE HBLOCK {
DOH *pp;
$$ = new_node("headerblock",$2.filename,$2.line);
Setattr($$,"code", $2.text);
Seek($2.text,0,SEEK_SET);
pp = Preprocessor_parse($2.text);
Seek(pp,0,SEEK_SET);
LParse_push(pp);
}
| RUNTIME HBLOCK {
$$ = new_node("runtimeblock",$2.filename,$2.line);
Setattr($$,"code",$2.text);
}
;
/* -- Documentation directives -- */
doc_directive : DOC_ENABLE { $$ = 0; }
| DOC_DISABLE { $$ = 0; }
/* %title directive */
| TITLE STRING styletail { $$ = 0; }
/* %section directive */
| SECTION STRING styletail { $$ = 0; }
/* %subsection directive */
| SUBSECTION STRING styletail { $$ = 0; }
/* %subsubsection directive */
| SUBSUBSECTION STRING styletail { $$ = 0; }
/* %text directive */
| TEXT HBLOCK { $$ = 0; }
/* Disable code generation */
| DOCONLY { $$ = 0; }
/* %style directive. This applies to all current styles */
| STYLE stylelist { $$ = 0; }
/* %localstyle directive. This applies only to the current style */
| LOCALSTYLE stylelist { $$ = 0; }
/* Documentation style list */
stylelist : ID stylearg styletail { $$ = 0; }
;
styletail : styletail COMMA ID stylearg { $$ = 0; }
| empty { $$ = 0; }
;
stylearg : EQUAL NUM_INT { }
| EQUAL STRING { }
| empty { }
;
idstring : ID { $$ = $1; }
| TYPE_TYPEDEF { $$ = $1; }
| STRING { $$ = $1; }
;
/* -- Exceptions -- */
except_directive: EXCEPT LPAREN ID RPAREN LBRACE {
DOH *t;
t = LParse_skip_balanced('{','}');
$$ = new_node("exceptiondirective",$1.filename,$1.line);
Setattr($$,"lang",$3.text);
Setattr($$,"code",t);
}
/* A Generic Exception (no language specified */
| EXCEPT LBRACE {
DOH *t;
t = LParse_skip_balanced('{','}');
$$ = new_node("exceptiondirective",$1.filename,$1.line);
Setattr($$,"code",t);
}
/* Clear an exception */
| EXCEPT LPAREN ID RPAREN SEMI {
$$ = new_node("exceptiondirective",$1.filename,$1.line);
Setattr($$,"lang",$3.text);
}
/* Generic clear */
| EXCEPT SEMI {
$$ = new_node("exceptiondirective",$1.filename,$1.line);
}
;
pragma_directive : PRAGMA ID pragma_arg {
$$ = new_node("pragmadirective",$1.filename,$1.line);
Setattr($$,ATTR_NAME,$2.text);
Setattr($$,ATTR_VALUE,$3.text);
}
| PRAGMA LPAREN ID RPAREN ID pragma_arg {
$$ = new_node("pragmadirective",$1.filename,$1.line);
Setattr($$,ATTR_NAME,$5.text);
Setattr($$,"lang",$3.text);
Setattr($$,ATTR_VALUE,$6.text);
}
;
pragma_arg : EQUAL definetype {
$$.text = $2.text;
}
| empty {
$$.text = 0;
}
;
/* A native wrapper function */
native_directive : NATIVE LBRACE interface RBRACE {
$$ = new_node("nativedirective",$1.filename,$1.line);
if ($3.node) {
Setattr($$,ATTR_CHILD,$3.node);
setparent($$,$3.node);
}
}
;
/* -- Typemap directives -- */
typemap_directive: TYPEMAP LPAREN ID COMMA tm_method RPAREN tm_list LBRACE {
DOH *o, *prev = 0, *t, *l;
int i;
t = LParse_skip_balanced('{','}');
$$ = 0;
for (i = 0; i < Len($7); i++) {
l = Getitem($7,i);
o = new_node("typemap",$1.filename, $1.line);
Setattr(o,"lang",$3.text);
Setattr(o,"method",$5.text);
Setattr(o,"code",t);
Setattr(o,ATTR_NAME,Getattr(l,ATTR_NAME));
Setattr(o,ATTR_TYPE,Getattr(l,ATTR_TYPE));
Setattr(o,ATTR_PARMS,Getattr(l,ATTR_PARMS));
if (!$$) $$ = o;
if (prev) {
Setattr(prev,ATTR_NEXT,o);
}
prev = o;
}
}
/* Create a new typemap in current language */
| TYPEMAP LPAREN tm_method RPAREN tm_list LBRACE {
DOH *o, *t, *l, *prev = 0;
int i;
t = LParse_skip_balanced('{','}');
$$ = 0;
for (i = 0; i < Len($5); i++) {
l = Getitem($5,i);
o = new_node("typemap",$1.filename, $1.line);
Setattr(o,"method",$3.text);
Setattr(o,"code",t);
Setattr(o,ATTR_NAME,Getattr(l,ATTR_NAME));
Setattr(o,ATTR_TYPE,Getattr(l,ATTR_TYPE));
Setattr(o,ATTR_PARMS,Getattr(l,ATTR_PARMS));
if (!$$) $$ = o;
if (prev) Setattr(prev,ATTR_NEXT,o);
prev = o;
}
}
/* Clear a typemap */
| TYPEMAP LPAREN ID COMMA tm_method RPAREN tm_list SEMI {
DOH *o, *l, *prev = 0;
int i;
$$ = 0;
for (i = 0; i < Len($7); i++) {
l = Getitem($7,i);
o = new_node("typemap",$1.filename, $1.line);
Setattr(o,"lang",$3.text);
Setattr(o,"method",$5.text);
Setattr(o,ATTR_NAME,Getattr(l,ATTR_NAME));
Setattr(o,ATTR_TYPE,Getattr(l,ATTR_TYPE));
if (!$$) $$ = o;
if (prev) Setattr(prev,ATTR_NEXT,o);
prev = o;
}
}
/* Clear a typemap in current language */
| TYPEMAP LPAREN tm_method RPAREN tm_list SEMI {
DOH *o, *l, *prev = 0;
int i;
$$ = 0;
for (i = 0; i < Len($5); i++) {
l = Getitem($5,i);
o = new_node("typemap",$1.filename, $1.line);
Setattr(o,"method",$3.text);
Setattr(o,ATTR_NAME,Getattr(l,ATTR_NAME));
Setattr(o,ATTR_TYPE,Getattr(l,ATTR_TYPE));
if (!$$) $$ = o;
if (prev) Setattr(prev,ATTR_NEXT,o);
prev = o;
}
}
/* Copy a typemap */
| TYPEMAP LPAREN ID COMMA tm_method RPAREN tm_list EQUAL tm_parm SEMI {
DOH *o, *l, *prev = 0;
int i;
$$ = 0;
for (i = 0; i < Len($7); i++) {
l = Getitem($7,i);
o = new_node("typemapcopy",$1.filename, $1.line);
Setattr(o,"method", $5.text);
Setattr(o,"lang", $3.text);
Setattr(o,ATTR_NAME, Getattr(l,ATTR_NAME));
Setattr(o,ATTR_TYPE, Getattr(l,ATTR_TYPE));
Setattr(o,ATTR_PARMS,Getattr(l,ATTR_PARMS));
Setattr(o,"srcname",Getattr($9,ATTR_NAME));
Setattr(o,"srctype",Getattr($9,ATTR_TYPE));
if (!$$) $$ = o;
if (prev) Setattr(prev,ATTR_NEXT,o);
prev = o;
}
}
/* Copy typemap in current language */
| TYPEMAP LPAREN tm_method RPAREN tm_list EQUAL tm_parm SEMI {
DOH *o, *l, *prev = 0;
int i;
$$ = 0;
for (i = 0; i < Len($5); i++) {
l = Getitem($5,i);
o = new_node("typemapcopy",$1.filename, $1.line);
Setattr(o,"method", $3.text);
Setattr(o,ATTR_NAME, Getattr(l,ATTR_NAME));
Setattr(o,ATTR_TYPE, Getattr(l,ATTR_TYPE));
Setattr(o,ATTR_PARMS,Getattr(l,ATTR_PARMS));
Setattr(o,"srcname",Getattr($7,ATTR_NAME));
Setattr(o,"srctype",Getattr($7,ATTR_TYPE));
if (!$$) $$ = o;
if (prev) Setattr(prev,ATTR_NEXT,o);
prev = o;
}
}
/* Apply directive */
| APPLY tm_parm LBRACE tm_list RBRACE {
$$ = new_node("applydirective",$1.filename, $1.line);
Setattr($$,ATTR_NAME,Getattr($2,ATTR_NAME));
Setattr($$,ATTR_TYPE,Getattr($2,ATTR_TYPE));
Setattr($$,ATTR_PARMS,$4);
}
/* Clear directive */
| CLEAR tm_list SEMI {
$$ = new_node("cleardirective",$1.filename, $1.line);
Setattr($$,ATTR_PARMS,$2);
}
;
tm_method : ID {
$$ = $1;
}
| CONST {
$$.text = NewString("const");
}
;
tm_list : tm_parm tm_tail {
Insert($2,0,$1);
$$ = $2;
}
;
tm_tail : COMMA tm_parm tm_tail {
Insert($3,0,$2);
$$ = $3;
}
| empty { $$ = NewList(); }
;
tm_parm : type tm_name {
$$ = NewHash();
if ($2.array) {
SwigType_push($1,$2.array);
}
Setattr($$,ATTR_TYPE,$1);
if ($2.name)
Setattr($$,ATTR_NAME,$2.name);
if ($2.parms)
Setattr($$,ATTR_PARMS,$2.parms);
}
| type stars tm_name {
$$ = NewHash();
SwigType_push($1,$2);
if ($3.array) {
SwigType_push($1,$3.array);
}
Setattr($$,ATTR_TYPE,$1);
if ($3.name)
Setattr($$,ATTR_NAME,$3.name);
if ($3.parms)
Setattr($$,ATTR_PARMS,$3.parms);
}
| type AND tm_name {
$$ = NewHash();
SwigType_add_reference($1);
if ($3.array) {
SwigType_push($1,$3.array);
}
Setattr($$,ATTR_TYPE,$1);
if ($3.name)
Setattr($$,ATTR_NAME,$3.name);
if ($3.parms)
Setattr($$,ATTR_PARMS,$3.parms);
}
;
tm_name : ID tm_args {
$$.parms = $2;
$$.name = $1.text;
$$.array = 0;
}
| ID array tm_args {
$$.name = $1.text;
$$.array = $2;
$$.parms = $3;
}
| array tm_args {
$$.name = 0;
$$.array = $1;
$$.parms = $2;
}
| tm_args {
$$.name = 0;
$$.array = 0;
$$.parms = $1;
}
;
tm_args : LPAREN parms RPAREN {
$$ = $2;
}
| empty {
$$ = 0;
}
;
map_directive : MAP ID LPAREN parms RPAREN LBRACE map_element RBRACE {
$$ = new_node("map", $1.filename, $1.line);
Setattr($$,ATTR_NAME,$2.text);
Setattr($$,ATTR_PARMS,$4);
/* Uh. Okay, this is a little nasty. We're going to take the
children and split them into rules and locals */
{
DOHHash *rules;
DOHHash *children = 0;
DOHHash *node, *nnode, *pnode;
rules = NewHash();
node = $7;
children = node;
pnode = 0;
while (node) {
nnode = Getattr(node,"next");
if (Cmp(Getattr(node,"tag"),"maprule") == 0) {
Setattr(rules,Getattr(node,"name"),Getattr(node,"code"));
if (pnode) {
if (nnode)
Setattr(pnode,"next",nnode);
else
Delattr(pnode,"next");
} else {
children = nnode;
}
Delete(node);
} else {
pnode = node;
}
node = nnode;
}
Setattr($$,"rules",rules);
if (children) {
Setattr($$,ATTR_CHILD,children);
setparent($$,children);
}
}
}
;
map_element : variable_decl map_element {
DOH *o, *o2;
$$ = $1;
o = $1;
while (o) {
o2 = o;
o = Getattr(o,ATTR_NEXT);
}
Setattr(o2,ATTR_NEXT,$2);
}
| function_decl map_element {
DOH *o, *o2;
$$ = $1;
o = $1;
while (o) {
o2 = o;
o = Getattr(o,ATTR_NEXT);
}
Setattr(o2,ATTR_NEXT,$2);
}
| STRING COLON LBRACE {
DOH *text = LParse_skip_balanced('{','}');
Delitem(text,0);
Delitem(text,DOH_END);
$$ = new_node("maprule",$1.filename, $1.line);
Setattr($$,ATTR_NAME,$1.text);
Setattr($$,"code",text);
$1.text = $$;
} map_element {
$$ = $1.text;
if ($5)
Setattr($$,ATTR_NEXT,$5);
}
| STRING COLON STRING SEMI {
$$ = new_node("maprule",$1.filename, $1.line);
Setattr($$,ATTR_NAME,$1.text);
Setattr($$,"code",$3.text);
$1.text = $$;
} map_element {
$$ = $1.text;
if ($6)
Setattr($$,ATTR_NEXT,$6);
}
| empty {
$$ = 0;
}
;
/* =============================================================================
* -- C Declarations --
* ============================================================================= */
c_declaration : variable_decl { $$ = $1; }
| function_decl { $$ = $1; }
| enum_decl { $$ = $1; }
| typedef_decl { $$ = $1; }
| cpp_decl { $$ = $1; }
;
/* A variable declaration */
variable_decl : storage_spec type declaration array2 def_args stail {
DOH *o, *t;
$$ = new_node(TAG_VARIABLE,Getfile($3.id),Getline($3.id));
t = Copy($2);
SwigType_push(t,$3.decl);
SwigType_push(t,$4);
Setattr($$,ATTR_NAME,$3.id);
Setattr($$,ATTR_TYPE,t);
if ($1.ivalue) {
Setattr($$,ATTR_STORAGE,$1.text);
}
if ($5.text) {
Setattr($$,ATTR_VALUE,$5.text);
}
if ($6) {
Setattr($$,ATTR_NEXT,$6);
o = $6;
while (o) {
t = Copy($2);
SwigType_push(t,Getattr(o,ATTR_TYPE));
Setattr(o,ATTR_TYPE,t);
if ($1.ivalue) {
Setattr(o,ATTR_STORAGE,$1.text);
}
o = Getattr(o,ATTR_NEXT);
}
}
}
/* Global variable that smells like a function pointer */
| storage_spec strict_type LPAREN STAR {
LParse_error($3.filename,$3.line,"Pointer to function not currently supported.\n");
LParse_skip_decl();
$$ = 0;
}
;
/* A function declaration */
function_decl : storage_spec type declaration LPAREN parms RPAREN cpp_const stail {
DOH *o, *t;
t = Copy($2);
SwigType_push(t,$3.decl);
$$ = new_node(TAG_FUNCTION,Getfile($3.id),Getline($3.id));
Setattr($$,ATTR_NAME,$3.id);
Setattr($$,ATTR_TYPE,t);
Setattr($$,ATTR_PARMS,$5);
if ($1.ivalue) {
Setattr($$,ATTR_STORAGE, $1.text);
}
if ($8) {
Setattr($$,ATTR_NEXT,$8);
o = $8;
while (o) {
t = Copy($2);
SwigType_push(t,Getattr(o,ATTR_TYPE));
Setattr(o,ATTR_TYPE,t);
if ($1.ivalue) {
Setattr(o,ATTR_STORAGE,$1.text);
}
o = Getattr(o,ATTR_NEXT);
}
}
}
/* A function declaration with code after it */
| storage_spec type declaration LPAREN parms RPAREN cpp_end {
SwigType_push($2,$3.decl);
$$ = new_node(TAG_FUNCTION,Getfile($3.id),Getline($3.id));
Setattr($$,ATTR_NAME,$3.id);
Setattr($$,ATTR_TYPE,$2);
Setattr($$,ATTR_PARMS,$5);
if ($1.ivalue) {
Setattr($$,ATTR_STORAGE, $1.text);
}
if ($7.text)
Setattr($$,"code",$7.text);
}
/* Possibly a constructor */
| storage_spec ID LPAREN parms RPAREN ctor_end {
DOH *t = NewString("int");
$$ = new_node(TAG_FUNCTION,$2.filename,$2.line);
Setattr($$,ATTR_NAME,$2.text);
Setattr($$,ATTR_TYPE,t);
Setattr($$,ATTR_PARMS,$4);
if ($1.ivalue) {
Setattr($$,ATTR_STORAGE,$1.text);
}
if ($6.text) {
Setattr($$,"code",$6.text);
}
}
/* A C++ destructor */
| NOT ID LPAREN parms RPAREN cpp_end {
$$ = new_node("destructor",$2.filename,$2.line);
Setattr($$,ATTR_NAME,$2.text);
if ($6.text) {
Setattr($$,"code",$6.text);
}
}
| NOT ID LPAREN parms RPAREN cpp_const SEMI {
$$ = new_node("destructor",$2.filename,$2.line);
Setattr($$,ATTR_NAME,$2.text);
}
;
/* Allow lists of variables and functions to be built up */
stail : SEMI { $$ = 0; }
| COMMA declaration array2 def_args stail {
DOH *t = NewString("");
SwigType_push(t,$2.decl);
SwigType_push(t,$3);
$$ = new_node(TAG_VARIABLE, Getfile($2.id),Getline($2.id));
Setattr($$,ATTR_NAME,$2.id);
Setattr($$,ATTR_TYPE,t);
if ($4.text)
Setattr($$,ATTR_VALUE,$4.text);
if ($5)
Setattr($$,ATTR_NEXT, $5);
}
| COMMA declaration LPAREN parms RPAREN stail {
DOH *t = NewString("");
SwigType_push(t,$2.decl);
$$ = new_node(TAG_FUNCTION, Getfile($2.id), Getline($2.id));
Setattr($$,ATTR_NAME,$2.id);
Setattr($$,ATTR_PARMS,$4);
Setattr($$,ATTR_TYPE, t);
if ($6)
Setattr($$,ATTR_NEXT,$6);
}
;
storage_spec : EXTERN {
$$.ivalue = 1;
$$.text = NewString("extern");
}
| EXTERN STRING {
$$.ivalue = 1;
$$.text = NewStringf("extern \"%s\"", $2.text);
}
| STATIC {
$$.ivalue = 1;
$$.text = NewString("static");
}
| empty {
$$.ivalue = 0;
$$.text = 0;
}
;
cpp_const : CONST {}
| THROW LPAREN { LParse_skip_balanced('(',')'); }
| empty {}
;
/* Enumerations */
enum_decl : storage_spec ENUM ename LBRACE enumlist RBRACE SEMI {
$$ = new_node("enum", $2.filename,$2.line);
Setattr($$,ATTR_NAME,$2.text);
Setattr($$,ATTR_CHILD,$5.node);
setparent($$,$5.node);
/* Add typename */
}
/* A typdef'd enum. Pretty common in C headers */
| TYPEDEF ENUM ename LBRACE enumlist RBRACE ID SEMI {
$$ = new_node("enum",$2.filename,$2.line);
Setattr($$,ATTR_NAME,$3.text);
Setattr($$,ATTR_CHILD,$5.node);
setparent($$,$5.node);
/* Add typedef for enum */
{
DOH *o;
o = new_node("typedef",$7.filename,$7.line);
Setattr(o,ATTR_NAME,$7.text);
Setattr(o,ATTR_TYPE,$3.text);
Setattr($$,ATTR_NEXT,o);
}
}
;
/* Some stuff for handling enums */
ename : ID { $$ = $1; }
| empty { $$.text = NewString(""); }
;
enumlist : enumlist COMMA edecl {
Setattr($1.last,ATTR_NEXT,$3);
$1.last = $3;
$$ = $1;
}
| edecl {
$$.node = $1;
$$.last = $1;
}
;
edecl : ID {
$$ = new_node(TAG_ENUMVALUE,$1.filename,$1.line);
Setattr($$,ATTR_NAME,$1.text);
}
| ID EQUAL expr {
$$ = new_node(TAG_ENUMVALUE,$1.filename,$1.line);
Setattr($$,ATTR_NAME,$1.text);
Setattr($$,ATTR_VALUE,$1.text);
}
| empty { $$ = 0; }
;
typedef_decl : TYPEDEF type declaration array2 typedeflist SEMI {
DOH *t, *d, *o, *ty, *prev;
int i;
$$ = new_node("typedef", $1.filename,$1.line);
t = Copy($2);
SwigType_push($2,$3.decl);
if ($4) SwigType_push($2,$4);
Setattr($$,ATTR_NAME,$3.id);
Setattr($$,ATTR_TYPE,$2);
/* Go create more typedefs */
prev = $$;
for (i = 0; i < Len($5); i++) {
DOH *ty;
d = Getitem($5,i);
o = new_node("typedef",$1.filename,$1.line);
ty = Copy(t);
SwigType_push(ty,Getattr(d,"decl"));
SwigType_push(ty,Getattr(d,"array"));
Setattr(o,ATTR_TYPE,ty);
Setattr(o,ATTR_NAME,Getattr(d,ATTR_NAME));
Setattr(prev,ATTR_NEXT,o);
prev = o;
}
Delete($5);
}
/* A rudimentary typedef involving function pointers */
| TYPEDEF type LPAREN stars pname RPAREN LPAREN parms RPAREN SEMI {
$$ = new_node("typedef", $1.filename,$1.line);
SwigType_push($2,parmstotype($8));
SwigType_push($2,$4);
if ($5.array)
SwigType_push($2,$5.array);
Setattr($$,ATTR_NAME,$5.name);
Setattr($$,ATTR_TYPE,$2);
}
/* A typedef involving function pointers again */
| TYPEDEF type stars LPAREN stars pname RPAREN LPAREN parms RPAREN SEMI {
$$ = new_node("typedef", $1.filename,$1.line);
SwigType_push($2,$3);
SwigType_push($2,parmstotype($9));
SwigType_push($2,$5);
if ($6.array)
SwigType_push($2,$6.array);
Setattr($$,ATTR_NAME,$6.name);
Setattr($$,ATTR_TYPE,$2);
}
;
typedeflist : COMMA declaration typedeflist {
DOH *o = NewHash();
Setattr(o,ATTR_NAME,$2.id);
Setattr(o,"decl",$2.decl);
Insert($3,0,o);
$$ = $3;
}
| COMMA declaration array typedeflist {
DOH *o;
$$ = $4;
o = NewHash();
Setattr(o,ATTR_NAME,$2.id);
Setattr(o,"decl",$2.decl);
if ($3)
Setattr(o,"array",$3);
Append($$,o);
}
| empty {
$$ = NewList();
}
;
/* =============================================================================
* -- Feeble C++ (yuck) Parsing --
* ============================================================================= */
cpp_decl : cpp_class { $$ = $1; }
| cpp_other { $$ = $1; }
;
cpp_class : storage_spec cpptype ID inherit LBRACE interface RBRACE opt_id SEMI {
$$ = new_node("class",$3.filename,$3.line);
Setattr($$,"classtype",$2.text);
Setattr($$,ATTR_NAME,$3.text);
Setattr($$,"bases", $4);
if ($6.node) {
Setattr($$,ATTR_CHILD,$6.node);
setparent($$,$6.node);
}
if ($8.text) {
Setattr($$,TAG_VARIABLE,$8.text);
}
}
| storage_spec cpptype LBRACE interface RBRACE opt_id SEMI {
$$ = new_node("class",$3.filename,$3.line);
Setattr($$,"classtype",$2.text);
if ($4.node) {
Setattr($$,ATTR_CHILD,$4.node);
setparent($$,$4.node);
}
if ($6.text)
Setattr($$,TAG_VARIABLE,$6.text);
}
/* Class with a typedef */
| TYPEDEF cpptype ID inherit LBRACE interface RBRACE declaration typedeflist {
$$ = new_node("class",$3.filename,$3.line);
Setattr($$,"classtype",$2.text);
Setattr($$,ATTR_NAME,$3.text);
Setattr($$,"bases",$4);
if ($6.node) {
Setattr($$,ATTR_CHILD,$6.node);
setparent($$,$6.node);
}
if (Len($8.decl) == 0)
Setattr($$,"altname",$8.id);
{
/* Go add a bunch of typedef declarations */
DOH *o, *t, *prev, *d;
int i;
o = new_node("typedef",$3.filename,$3.line);
Setattr(o,ATTR_NAME,$8.id);
t = Copy($3.text);
SwigType_push(t,$8.decl);
Setattr(o,ATTR_TYPE,t);
Setattr($$,ATTR_NEXT,o);
prev = o;
for (i = 0; i < Len($9); i++) {
d = Getitem($9,i);
o = new_node("typedef",$3.filename,$3.line);
t = Copy($3.text);
SwigType_push(t,Getattr(d,"decl"));
SwigType_push(t,Getattr(d,"array"));
Setattr(o,ATTR_TYPE,t);
Setattr(o,ATTR_NAME,Getattr(d,ATTR_NAME));
Setattr(prev,ATTR_NEXT,o);
prev = o;
}
Delete($9);
}
}
/* An unnamed struct with a typedef */
| TYPEDEF cpptype LBRACE interface RBRACE declaration typedeflist {
$$ = new_node("class",$3.filename,$3.line);
Setattr($$,"classtype",$2.text);
if ($4.node) {
Setattr($$,ATTR_CHILD,$4.node);
setparent($$,$4.node);
}
if (Len($6.decl) == 0)
Setattr($$,"altname",$6.id);
}
;
inherit : COLON base_list {
$$ = $2;
}
| empty {
$$ = 0;
}
;
base_list : base_specifier {
$$ = NewList();
Append($$,$1.text);
}
| base_list COMMA base_specifier {
$$ = $1;
if ($3.text)
Append($$,$3.text);
}
;
base_specifier : ID {
LParse_error($1.filename,$1.line,"No access specifier given for base class %s (ignored).\n", $1.text);
$$.text = 0;
}
| access_specifier ID {
if (Cmp($1.text,"public") == 0) {
$$ = $2;
} else {
LParse_error($2.filename,$2.line,"%s inheritance not supported (ignored).\n", $1.text);
$$.text = 0;
}
}
;
access_specifier : PUBLIC { $$.text = NewString("public"); }
| PRIVATE { $$.text = NewString("private"); }
| PROTECTED { $$.text = NewString("protected"); }
;
cpp_end : cpp_const LBRACE {
$$.text = LParse_skip_balanced('{','}');
}
| EQUAL definetype SEMI {
$$.text = 0;
}
/* | cpp_const {
$$.text = 0;
}
*/
;
type_extra : stars {}
| AND {}
| empty {}
;
/* Constructor initializer */
ctor_end : cpp_const ctor_initializer SEMI { $$.text = 0; }
| cpp_const ctor_initializer LBRACE { $$.text = LParse_skip_balanced('{','}'); }
;
ctor_initializer : COLON mem_initializer_list {}
| empty {}
;
mem_initializer_list : mem_initializer { }
| mem_initializer_list COMMA mem_initializer { }
;
mem_initializer : ID LPAREN { LParse_skip_balanced('(',')'); }
;
cpp_other :/* A dummy class name */
storage_spec cpptype ID SEMI {
DOH *o = new_node("classdecl",$4.filename,$4.line);
Setattr(o,ATTR_NAME,$3.text);
}
| PUBLIC COLON { $$ = new_node("public",$1.filename,$1.line); }
| PRIVATE COLON { $$ = new_node("private",$1.filename,$1.line); }
| PROTECTED COLON { $$ = new_node("protected",$1.filename,$1.line); }
| FRIEND {
LParse_skip_decl();
}
| storage_spec type type_extra OPERATOR {
LParse_skip_decl();
}
/* Any sort of out-of-class C++ declaration */
| storage_spec type declaration DCOLON {
LParse_skip_decl();
}
/* Template catch */
| TEMPLATE {
LParse_skip_decl();
}
/* %addmethods directive */
| ADDMETHODS opt_id LBRACE interface RBRACE {
$$ = new_node("addmethods",$1.filename,$1.line);
if ($1.text)
Setattr($$,ATTR_NAME,$1.text);
if ($4.node) {
Setattr($$,ATTR_CHILD,$4.node);
setparent($$,$4.node);
}
}
opt_id : ID { $$ = $1; }
| empty { $$.text = 0; }
;
/* =============================================================================
* -- Generic (admittedly poor) C Parsing --
* ============================================================================= */
/* -- Function parameter lists -- */
parms : parm ptail {
if ($2) {
Setattr($1,ATTR_NEXT,$2);
Setattr($2,ATTR_PREV,$1);
}
$$ = $1;
}
| empty { $$ = 0; }
;
ptail : COMMA parm ptail {
if ($3) {
Setattr($2,ATTR_NEXT,$3);
Setattr($3,ATTR_PREV,$2);
}
$$ = $2;
}
| empty { $$ = 0; }
;
parm : type pname {
$$ = new_node("parm",Getfile($2.name),Getline($2.name));
Setattr($$,ATTR_NAME,$2.name);
SwigType_push($1,$2.array);
if ($2.value)
Setattr($$,ATTR_VALUE,$2.value);
Setattr($$,ATTR_TYPE,$1);
}
| type stars pname {
$$ = new_node("parm",Getfile($3.name),Getline($3.name));
Setattr($$,ATTR_NAME,$3.name);
SwigType_push($1,$2);
SwigType_push($1,$3.array);
if ($3.value) {
Setattr($$,ATTR_VALUE,$3.value);
}
Setattr($$,ATTR_TYPE,$1);
}
| type AND pname {
$$ = new_node("parm",Getfile($3.name),Getline($3.name));
SwigType_add_reference($1);
SwigType_push($1,$3.array);
Setattr($$,ATTR_NAME,$3.name);
if ($3.value) {
Setattr($$,ATTR_VALUE,$3.value);
}
Setattr($$,ATTR_TYPE,$1);
}
| type LPAREN stars pname RPAREN LPAREN parms RPAREN {
$$ = new_node("parm",$2.filename, $2.line);
SwigType_push($1,parmstotype($7));
SwigType_push($1,$3);
if ($4.array)
SwigType_push($1,$4.array);
Setattr($$,ATTR_NAME,$4.name);
if ($4.value)
Setattr($$,ATTR_VALUE,$4.value);
Setattr($$,ATTR_TYPE,$1);
}
| type stars LPAREN stars pname RPAREN LPAREN parms RPAREN {
$$ = new_node("parm",$3.filename, $3.line);
SwigType_push($1,$2);
SwigType_push($1,parmstotype($8));
SwigType_push($1,$4);
if ($5.array)
SwigType_push($1,$5.array);
Setattr($$,ATTR_NAME,$5.name);
if ($5.value)
Setattr($$,ATTR_VALUE,$5.value);
Setattr($$,ATTR_TYPE,$1);
}
| PERIOD PERIOD PERIOD {
$$ = new_node("parm",$1.filename,$1.line);
Setattr($$,ATTR_NAME,"...");
Setattr($$,ATTR_TYPE,"?");
}
;
pname : ID def_args {
$$.name = $1.text;
$$.value = $2.text;
$$.array = 0;
}
| ID array {
$$.name = $1.text;
$$.value = 0;
$$.array = $2;
}
| array {
$$.name = NewString("");
$$.value = 0;
$$.array = $1;
}
| empty {
$$.name = NewString("");
$$.value = 0;
$$.array = 0;
}
;
def_args : EQUAL definetype { $$ = $2; }
| EQUAL AND ID {
$$.text = NewString("");
Printf($$.text,"&%s",$3.text);
$$.ivalue = LPARSE_T_USER;
}
| EQUAL LBRACE {
LParse_skip_balanced('{','}');
$$.text = 0;
$$.ivalue = 0;
}
| COLON NUM_INT {
$$.text = 0;
$$.ivalue = 0;
}
| empty {
$$.text = 0;
$$.ivalue = 0;
}
;
/* Declaration must be an identifier, possibly preceded by a * for pointer types */
declaration : ID {
$$.id = $1.text;
$$.decl = NewString("");
}
| stars ID {
$$.id = $2.text;
$$.decl = $1;
}
| AND ID {
$$.id = $2.text;
$$.decl = NewString("");
SwigType_add_reference($$.decl);
}
| AND stars ID {
$$.id = $3.text;
$$.decl = $2;
SwigType_add_reference($$.decl);
}
;
stars : STAR empty {
$$ = NewString("");
SwigType_add_pointer($$);
}
| STAR stars {
$$ = $2;
SwigType_add_pointer($$);
}
;
array : LBRACKET RBRACKET array2 {
$$ = $3;
SwigType_add_array($$,"");
}
| LBRACKET expr RBRACKET array2 {
$$ = $4;
SwigType_add_array($$,$2.text);
}
;
array2 : array {
$$ = $1;
}
| empty { $$ = NewString(""); }
;
type : TYPE_INT { $$ = NewString("int"); }
| TYPE_SHORT opt_int { $$ = NewString("short"); }
| TYPE_LONG opt_int { $$ = NewString("long"); }
| TYPE_CHAR { $$ = NewString("char"); }
| TYPE_BOOL { $$ = NewString("bool"); }
| TYPE_FLOAT { $$ = NewString("float"); }
| TYPE_DOUBLE { $$ = NewString("double"); }
| TYPE_VOID { $$ = NewString("void"); }
| TYPE_SIGNED opt_signed {
if ($2) $$ = $2;
else {
$$ = NewString("signed");
}
}
| TYPE_UNSIGNED opt_unsigned {
if ($2) $$ = $2;
else {
$$ = NewString("unsigned");
}
}
| ID template_decl {
if ($2.text)
$$ = NewStringf("%s%s",$1.text,$2.text);
else
$$ = NewString($1.text);
}
| CONST type {
SwigType_add_qualifier($2,"const");
$$ = $2;
}
| cpptype ID {
$$ = NewStringf("%s %s", $1.text, $2.text);
}
| ID DCOLON ID {
$$ = NewStringf("%s::%s",$1.text,$2.text);
}
/* This declaration causes a shift-reduce conflict. Unresolved for now */
| DCOLON ID {
$$ = Copy($2.text);
}
| ENUM ID {
$$ = NewStringf("enum %s", $2.text);
}
;
strict_type : TYPE_INT { $$ = NewString("int"); }
| TYPE_SHORT opt_int { $$ = NewString("short"); }
| TYPE_LONG opt_int { $$ = NewString("long"); }
| TYPE_CHAR { $$ = NewString("char"); }
| TYPE_BOOL { $$ = NewString("bool"); }
| TYPE_FLOAT { $$ = NewString("float"); }
| TYPE_DOUBLE { $$ = NewString("double"); }
| TYPE_VOID { $$ = NewString("void"); }
| TYPE_SIGNED opt_signed {
if ($2) $$ = $2;
else {
$$ = NewString("signed");
}
}
| TYPE_UNSIGNED opt_unsigned {
if ($2) $$ = $2;
else {
$$ = NewString("unsigned");
}
}
| TYPE_TYPEDEF template_decl {
if ($2.text) {
$$ = NewStringf("%s%s",$1.text,$2.text);
} else {
$$ = NewString($1.text);
}
}
| CONST type {
$$ = $2;
SwigType_add_qualifier($$,"const");
}
| cpptype ID {
$$ = NewStringf("%s %s", $1.text, $2.text);
}
| ENUM ID {
$$ = NewStringf("enum %s", $2.text);
}
;
template_decl : LESSTHAN {
$$.text = LParse_skip_balanced('<','>');
}
| empty { $$.text = 0; }
;
/* Optional signed types */
opt_signed : empty { $$ = 0; }
| TYPE_INT {
$$ = NewString("signed int");
}
| TYPE_SHORT opt_int {
$$ = NewString("signed short");
}
| TYPE_LONG opt_int {
$$ = NewString("signed long");
}
| TYPE_CHAR {
$$ = NewString("signed char");
}
;
/* Optional unsigned types */
opt_unsigned : empty { $$ = 0;}
| TYPE_INT {
$$ = NewString("unsigned int");
}
| TYPE_SHORT opt_int {
$$ = NewString("unsigned short");
}
| TYPE_LONG opt_int {
$$ = NewString("unsigned long");
}
| TYPE_CHAR {
$$ = NewString("unsigned char");
}
;
opt_int : TYPE_INT { }
| empty { }
;
cpptype : CLASS { $$ = $1; }
| STRUCT { $$ = $1; }
| UNION { $$ = $1; }
;
/* -----------------------------------------------------------------------------
* -- Expressions --
* ----------------------------------------------------------------------------- */
definetype : expr {
$$ = $1;
}
| STRING {
$$.text = $1.text;
$$.ivalue = LPARSE_T_STRING;
}
;
expr : NUM_INT {
$$.text = $1.text;
$$.ivalue = LPARSE_T_INT;
}
| NUM_FLOAT {
$$.text = $1.text;
$$.ivalue = LPARSE_T_DOUBLE;
}
| NUM_UNSIGNED {
$$.text = $1.text;
$$.ivalue = LPARSE_T_UINT;
}
| NUM_LONG {
$$.text = $1.text;
$$.ivalue = LPARSE_T_LONG;
}
| NUM_ULONG {
$$.text = $1.text;
$$.ivalue = LPARSE_T_ULONG;
}
| CHARCONST {
$$.text = NewString("");
Printf($$.text,"\'%s\'", $1.text);
$$.ivalue = LPARSE_T_CHAR;
}
| SIZEOF LPAREN {
$$.text = NewString("sizeof(");
Append($$.text,LParse_skip_balanced('(',')'));
$$.ivalue = LPARSE_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 = LPARSE_T_INT;
}
| ID DCOLON ID {
$$.id = new char[strlen($1)+strlen($3)+3];
sprintf($$.id,"%s::%s",$1,$3);
$$.type = LPARSE_T_INT;
delete $1;
delete $3;
}
*/
| expr PLUS expr {
$$.text = NewString("");
Printf($$.text,"%s+%s", $1.text,$3.text);
$$.ivalue = promote($1.ivalue,$3.ivalue);
}
| expr MINUS expr {
$$.text = NewString("");
Printf($$.text,"%s-%s", $1.text,$3.text);
$$.ivalue = promote($1.ivalue,$3.ivalue);
}
| expr STAR expr {
$$.text = NewString("");
Printf($$.text,"%s*%s", $1.text,$3.text);
$$.ivalue = promote($1.ivalue,$3.ivalue);
}
| expr SLASH expr {
$$.text = NewString("");
Printf($$.text,"%s/%s", $1.text,$3.text);
$$.ivalue = promote($1.ivalue,$3.ivalue);
}
| expr AND expr {
$$.text = NewString("");
Printf($$.text,"%s&%s", $1.text,$3.text);
$$.ivalue = promote($1.ivalue,$3.ivalue);
if (($1.ivalue == LPARSE_T_DOUBLE) || ($3.ivalue == LPARSE_T_DOUBLE)) {
LParse_error($2.filename,$2.line,"Type error in constant expression (expecting integers).\n");
}
}
| expr OR expr {
$$.text = NewString("");
Printf($$.text,"%s|%s", $1.text,$3.text);
$$.ivalue = promote($1.ivalue,$3.ivalue);
if (($1.ivalue == LPARSE_T_DOUBLE) || ($3.ivalue == LPARSE_T_DOUBLE)) {
LParse_error($2.filename,$2.line,"Type error in constant expression (expecting integers).\n");
}
$$.ivalue = LPARSE_T_INT;
}
| expr XOR expr {
$$.text = NewString("");
Printf($$.text,"%s^%s", $1.text,$3.text);
$$.ivalue = promote($1.ivalue,$3.ivalue);
if (($1.ivalue == LPARSE_T_DOUBLE) || ($3.ivalue == LPARSE_T_DOUBLE)) {
LParse_error($2.filename,$2.line,"Type error in constant expression (expecting integers).\n");
}
$$.ivalue = LPARSE_T_INT;
}
| expr LSHIFT expr {
$$.text = NewString("");
Printf($$.text,"%s<<%s", $1.text,$3.text);
$$.ivalue = promote($1.ivalue,$3.ivalue);
if (($1.ivalue == LPARSE_T_DOUBLE) || ($3.ivalue == LPARSE_T_DOUBLE)) {
LParse_error($2.filename,$2.line,"Type error in constant expression (expecting integers).\n");
}
$$.ivalue = LPARSE_T_INT;
}
| expr RSHIFT expr {
$$.text = NewString("");
Printf($$.text,"%s>>%s", $1.text,$3.text);
$$.ivalue = promote($1.ivalue,$3.ivalue);
if (($1.ivalue == LPARSE_T_DOUBLE) || ($3.ivalue == LPARSE_T_DOUBLE)) {
LParse_error($2.filename,$2.line,"Type error in constant expression (expecting integers).\n");
}
$$.ivalue = LPARSE_T_INT;
}
| MINUS expr %prec UMINUS {
$$.text = NewString("");
Printf($$.text,"-%s", $2.text);
$$.ivalue = $2.ivalue;
}
| NOT expr {
$$.text = NewString("");
Printf($$.text,"~%s", $2.text);
if ($2.ivalue == LPARSE_T_DOUBLE) {
LParse_error($2.filename,$2.line,"Type error in constant expression (expecting integers).\n");
}
$$.ivalue = $2.ivalue;
}
| LPAREN expr RPAREN {
$$.text = NewString("");
Printf($$.text,"(%s)", $2.text);
$$.ivalue = $2.ivalue;
}
;
idlist : idlist COMMA ID {
Append($$,$3.text);
}
| empty {
$$ = NewList();
}
;
empty : ;
%%
void lparse_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 *e) {
LParse_error(0,0,"Syntax error.\n", e);
}