From 5e09b2232c6cccc6626aa91987872220bd8712fc Mon Sep 17 00:00:00 2001 From: Dave Beazley Date: Wed, 19 Jan 2000 03:27:34 +0000 Subject: [PATCH] Initial checkin git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@110 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- Source/LParse/Makefile.in | 32 + Source/LParse/cscanner.c | 388 +++++++ Source/LParse/lparse.h | 98 ++ Source/LParse/parser.y | 2038 +++++++++++++++++++++++++++++++++++++ Source/LParse/type.c | 407 ++++++++ 5 files changed, 2963 insertions(+) create mode 100644 Source/LParse/Makefile.in create mode 100644 Source/LParse/cscanner.c create mode 100644 Source/LParse/lparse.h create mode 100644 Source/LParse/parser.y create mode 100644 Source/LParse/type.c diff --git a/Source/LParse/Makefile.in b/Source/LParse/Makefile.in new file mode 100644 index 000000000..513f867bd --- /dev/null +++ b/Source/LParse/Makefile.in @@ -0,0 +1,32 @@ +# Generated automatically from Makefile.in by configure. + +CC = @CC@ +AR = @AR@ +RANLIB = @RANLIB@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +RPATH = @RPATH@ +SO = @SO@ +CCSHARED = @CCSHARED@ +LDSHARED = @LDSHARED@ +INCLUDE = -I. -I../Swig -I../DOH/Include -I../Preprocessor + +SRCS = cscanner.c type.c +OBJS = cscanner.o type.o + +.c.o: + $(CC) $(CCSHARED) $(INCLUDE) $(CFLAGS) -c -o $*.o $< + +all: parser.o $(OBJS) + +parser.o: parser.c + $(CC) $(CCSHARED) $(INCLUDE) $(CFLAGS) -c -o $*.o $< + +parser.c: parser.y + $(YACC) -d parser.y + @cp y.tab.h lyacc.h + @cp y.tab.c parser.c + +clean: + rm -f *.o *~ core *.so *.a y.tab* + diff --git a/Source/LParse/cscanner.c b/Source/LParse/cscanner.c new file mode 100644 index 000000000..8c172d4f0 --- /dev/null +++ b/Source/LParse/cscanner.c @@ -0,0 +1,388 @@ +/******************************************************************************* + * 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$ + * + * scanner.c + * ----------------------------------------------------------------------------- */ + +#include "lparse.h" + +#define yylval lparse_yylval + +#include "lyacc.h" +#include + +static int map[][2] = { + { SWIG_TOKEN_LPAREN, LPAREN }, + { SWIG_TOKEN_RPAREN, RPAREN }, + { SWIG_TOKEN_SEMI, SEMI }, + { SWIG_TOKEN_COMMA, COMMA }, + { SWIG_TOKEN_STAR, STAR }, + { SWIG_TOKEN_LBRACE, LBRACE }, + { SWIG_TOKEN_RBRACE, RBRACE }, + { SWIG_TOKEN_EQUAL, EQUAL }, + { SWIG_TOKEN_EQUALTO, EQUALTO }, + { SWIG_TOKEN_NOTEQUAL, NOTEQUAL }, + { SWIG_TOKEN_PLUS, PLUS }, + { SWIG_TOKEN_MINUS, MINUS }, + { SWIG_TOKEN_AND, AND }, + { SWIG_TOKEN_LAND, LAND }, + { SWIG_TOKEN_OR, OR}, + { SWIG_TOKEN_LOR, LOR}, + { SWIG_TOKEN_XOR, XOR}, + { SWIG_TOKEN_LESSTHAN, LESSTHAN }, + { SWIG_TOKEN_GREATERTHAN, GREATERTHAN }, + { SWIG_TOKEN_LTEQUAL, LTEQUAL}, + { SWIG_TOKEN_GTEQUAL, GTEQUAL}, + { SWIG_TOKEN_NOT, NOT }, + { SWIG_TOKEN_LNOT, LNOT }, + { SWIG_TOKEN_LBRACKET, LBRACKET }, + { SWIG_TOKEN_RBRACKET, RBRACKET }, + { SWIG_TOKEN_SLASH, SLASH }, + { SWIG_TOKEN_BACKSLASH, -1 }, + { SWIG_TOKEN_ENDLINE, -1}, + { SWIG_TOKEN_STRING, STRING }, + { SWIG_TOKEN_POUND, POUND }, + { SWIG_TOKEN_PERCENT, -1 }, + { SWIG_TOKEN_COLON, COLON }, + { SWIG_TOKEN_DCOLON, DCOLON }, + { SWIG_TOKEN_LSHIFT, LSHIFT }, + { SWIG_TOKEN_RSHIFT, RSHIFT }, + { SWIG_TOKEN_ID, ID}, + { SWIG_TOKEN_FLOAT, NUM_FLOAT}, + { SWIG_TOKEN_DOUBLE, NUM_FLOAT}, + { SWIG_TOKEN_INT, NUM_INT}, + { SWIG_TOKEN_UINT, NUM_UNSIGNED}, + { SWIG_TOKEN_LONG, NUM_LONG}, + { SWIG_TOKEN_ULONG, NUM_ULONG}, + { SWIG_TOKEN_CHAR, CHARCONST}, + { SWIG_TOKEN_PERIOD, PERIOD}, + { SWIG_TOKEN_AT, -1}, + { SWIG_TOKEN_DOLLAR, -1}, + { SWIG_TOKEN_CODEBLOCK, HBLOCK}, + { SWIG_TOKEN_ILLEGAL, SWIG_TOKEN_ILLEGAL}, + { SWIG_TOKEN_LAST, -1}, + {0,0}, +}; + +static int remap[SWIG_MAXTOKENS]; +static int cscan_init = 0; +static int cplusplus_mode = 0; +static int objc_mode = 0; +static SwigScanner *cscanner = 0; + +/* ----------------------------------------------------------------------------- + * void lparse_init() + * ----------------------------------------------------------------------------- */ + +static void +lparse_init() { + int i = 0; + if (cscan_init) return; + while (map[i][0]) { + remap[map[i][0]] = map[i][1]; + i++; + } + cscanner = NewSwigScanner(); + SwigScanner_idstart(cscanner,"$%@"); + cscan_init = 1; +} + +/* ----------------------------------------------------------------------------- + * LParse_push(DOH *str) - Initialize the scanner + * ----------------------------------------------------------------------------- */ +void +LParse_push(DOH *str) +{ + assert(str); + lparse_init(); + SwigScanner_push(cscanner, str); +} + +DOH *LParse_file() { + return SwigScanner_get_file(cscanner); +} + +int LParse_line() { + return SwigScanner_get_line(cscanner); +} + +void LParse_set_location(DOH *file, int line) { + SwigScanner_set_location(cscanner,file,line); +} + +/* ----------------------------------------------------------------------------- + * LParse_cplusplus(int i) - Enable C++ scanning + * ----------------------------------------------------------------------------- */ +int +LParse_cplusplus(int i) { + int old = cplusplus_mode; + cplusplus_mode = i; + return old; +} + +/* ----------------------------------------------------------------------------- + * LParse_objc(int i) - Enable Objective-C scanning + * ----------------------------------------------------------------------------- */ +int +LParse_objc(int i) { + int old = objc_mode; + objc_mode = i; + return old; +} + +/* ----------------------------------------------------------------------------- + * LParse_error(DOH *file, int line, char *fmt, ...) + * ----------------------------------------------------------------------------- */ + +static DOH *macro_name = 0; +static DOH *macro_file = 0; +static int macro_line = 0; + +void LParse_macro_location(DOH *name, DOH *file, int line) { + macro_name = name; + macro_file = file; + macro_line = line; +} +void LParse_error(DOH *file, int line, char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + if (!file) { + file = SwigScanner_get_file(cscanner); + line = SwigScanner_get_line(cscanner); + } + if (macro_name) { + Printf(stderr,"%s:%d In macro %s at ", macro_file, macro_line, macro_name); + } + if (line > 0) { + Printf(stderr,"%s:%d ", file, line); + } else { + Printf(stderr,"%s:EOF ",file); + } + vPrintf(stderr,fmt,ap); + va_end(ap); + macro_name = 0; +} + +/* ----------------------------------------------------------------------------- + * LParse_skip_balanced() - Skip over some text + * ----------------------------------------------------------------------------- */ +DOH * +LParse_skip_balanced(int startchar, int endchar) +{ + DOH *file; + int line; + file = SwigScanner_get_file(cscanner); + line = SwigScanner_get_line(cscanner); + if (SwigScanner_skip_balanced(cscanner, startchar, endchar) == -1) + LParse_error(file,line,"Missing \'%c\'. Reached the end of input.\n", endchar); + return Copy(SwigScanner_text(cscanner)); +} + +/* ----------------------------------------------------------------------------- + * LParse_skip_semi() - Skip to the next semicolon + * ----------------------------------------------------------------------------- */ +void +LParse_skip_semi() { + int t, line; + DOH *file; + int lparse_yylex(); + + line = SwigScanner_get_line(cscanner); + file = SwigScanner_get_file(cscanner); + while ((t = lparse_yylex())) { + if (t == SEMI) return; + } + LParse_error(file,line,"Missing semicolon. Reached the end of input.\n"); +} + +void +LParse_skip_decl() { + int t, line, level = 0; + DOH *file; + int lparse_yylex(); + + line = SwigScanner_get_line(cscanner); + file = SwigScanner_get_file(cscanner); + while ((t = lparse_yylex())) { + if ((t == SEMI) && (level == 0)) return; + if (t == LBRACE) level++; + if (t == RBRACE) { + level--; + if (level <= 0) return; + } + } + if (level) { + LParse_error(file,line,"Missing \'}\'. Reached the end of input.\n"); + } else { + LParse_error(file,line,"Missing semicolon. Reached the end of input.\n"); + } +} + +/* ----------------------------------------------------------------------------- + * int lparse_yylex() - Entry point called by the parser + * ----------------------------------------------------------------------------- */ +static int +yylex1(void) { + int l, l1; + DOH *text; + char *yytext = 0; + int lparse_yylex(); + + assert(cscan_init); + l = SwigScanner_token(cscanner); + if (!l) return 0; + l1 = remap[l]; + if (l1 == -1) return lparse_yylex(); + + text = SwigScanner_text(cscanner); + yylval.tok.line = Getline(text); + yylval.tok.filename = Getfile(text); + yylval.tok.data = 0; + yylval.tok.ivalue = 0; + yytext = Char(text); + if (l1 == SWIG_TOKEN_ILLEGAL) { + LParse_error(0,0,"Illegal character '%s'\n", text); + return yylex1(); + } + if (l1 == STRING) { + yylval.tok.text = NewString(yytext+1); + Delitem(yylval.tok.text,DOH_END); + } + if ((l1 == HBLOCK) || (l1 == NUM_INT) || (l1 == NUM_FLOAT) || (l1 == NUM_UNSIGNED) || (l1 == NUM_LONG) || (l1 == NUM_ULONG)) { + yylval.tok.text = NewString(yytext); + } + if (l1 == ID) { + /* Look for keywords now */ + if (strcmp(yytext,"int") == 0) return(TYPE_INT); + if (strcmp(yytext,"double") == 0) return(TYPE_DOUBLE); + if (strcmp(yytext,"void") == 0) return(TYPE_VOID); + if (strcmp(yytext,"char") == 0) return(TYPE_CHAR); + if (strcmp(yytext,"short") == 0) return(TYPE_SHORT); + if (strcmp(yytext,"long") == 0) return(TYPE_LONG); + if (strcmp(yytext,"float") == 0) return(TYPE_FLOAT); + if (strcmp(yytext,"signed") == 0) return(TYPE_SIGNED); + if (strcmp(yytext,"unsigned") == 0) return(TYPE_UNSIGNED); + if (strcmp(yytext,"bool") == 0) return(TYPE_BOOL); + + /* C++ keywords */ + + if (1 || cplusplus_mode) { + if (strcmp(yytext,"class") == 0) { + yylval.tok.text = NewString(yytext); + return(CLASS); + } + if (strcmp(yytext,"private") == 0) return(PRIVATE); + if (strcmp(yytext,"public") == 0) return(PUBLIC); + if (strcmp(yytext,"protected") == 0) return(PROTECTED); + if (strcmp(yytext,"friend") == 0) return(FRIEND); + if (strcmp(yytext,"virtual") == 0) return(VIRTUAL); + if (strcmp(yytext,"operator") == 0) return(OPERATOR); + if (strcmp(yytext,"throw") == 0) return(THROW); + if (strcmp(yytext,"inline") == 0) return(lparse_yylex()); + if (strcmp(yytext,"template") == 0) return(TEMPLATE); + } + /* Objective-C keywords */ + + if (objc_mode) { + if (strcmp(yytext,"@interface") == 0) return (OC_INTERFACE); + if (strcmp(yytext,"@end") == 0) return (OC_END); + if (strcmp(yytext,"@public") == 0) return (OC_PUBLIC); + if (strcmp(yytext,"@private") == 0) return (OC_PRIVATE); + if (strcmp(yytext,"@protected") == 0) return (OC_PROTECTED); + if (strcmp(yytext,"@class") == 0) return(OC_CLASS); + if (strcmp(yytext,"@implementation") == 0) return(OC_IMPLEMENT); + if (strcmp(yytext,"@protocol") == 0) return(OC_PROTOCOL); + } + + /* Misc keywords */ + if (strcmp(yytext,"static") == 0) return(STATIC); + if (strcmp(yytext,"extern") == 0) return(EXTERN); + if (strcmp(yytext,"const") == 0) return(CONST); + if (strcmp(yytext,"struct") == 0) { + yylval.tok.text = NewString(yytext); + return(STRUCT); + } + if (strcmp(yytext,"union") == 0) { + yylval.tok.text = NewString(yytext); + return(UNION); + } + if (strcmp(yytext,"enum") == 0) return(ENUM); + if (strcmp(yytext,"sizeof") == 0) return(SIZEOF); + if (strcmp(yytext,"defined") == 0) return(DEFINED); + + /* Ignored keywords */ + if (strcmp(yytext,"volatile") == 0) return(lparse_yylex()); + + /* SWIG directives */ + if (strcmp(yytext,"%module") == 0) return(MODULE); + if (strcmp(yytext,"%constant") == 0) return (CONSTANT); + if (strcmp(yytext,"%type") == 0) return (TYPE); + if (strcmp(yytext,"%init") == 0) return(INIT); + if (strcmp(yytext,"%wrapper") == 0) return(WRAPPER); + if (strcmp(yytext,"%readonly") == 0) return(READONLY); + if (strcmp(yytext,"%readwrite") == 0) return(READWRITE); + if (strcmp(yytext,"%name") == 0) return(NAME); + if (strcmp(yytext,"%rename") == 0) return(RENAME); + if (strcmp(yytext,"%include") == 0) return(INCLUDE); + if (strcmp(yytext,"%extern") == 0) return(WEXTERN); + if (strcmp(yytext,"%checkout") == 0) return(CHECKOUT); + if (strcmp(yytext,"%macro") == 0) return(MACRO); + if (strcmp(yytext,"%section") == 0) return(SECTION); + if (strcmp(yytext,"%subsection") == 0) return(SUBSECTION); + if (strcmp(yytext,"%subsubsection") == 0) return(SUBSUBSECTION); + if (strcmp(yytext,"%title") == 0) return(TITLE); + if (strcmp(yytext,"%style") == 0) return(STYLE); + if (strcmp(yytext,"%localstyle") == 0) return(LOCALSTYLE); + if (strcmp(yytext,"%typedef") == 0) return(TYPEDEF); + if (strcmp(yytext,"typedef") == 0) return(TYPEDEF); + if (strcmp(yytext,"%alpha") == 0) return(ALPHA_MODE); + if (strcmp(yytext,"%raw") == 0) return(RAW_MODE); + if (strcmp(yytext,"%text") == 0) return(TEXT); + if (strcmp(yytext,"%native") == 0) return(NATIVE); + if (strcmp(yytext,"%disabledoc") == 0) return(DOC_DISABLE); + if (strcmp(yytext,"%enabledoc") == 0) return(DOC_ENABLE); + if (strcmp(yytext,"%pragma") == 0) return(PRAGMA); + if (strcmp(yytext,"%addmethods") == 0) return(ADDMETHODS); + if (strcmp(yytext,"%inline") == 0) return(INLINE); + if (strcmp(yytext,"%typemap") == 0) return(TYPEMAP); + if (strcmp(yytext,"%except") == 0) return(EXCEPT); + if (strcmp(yytext,"%import") == 0) return(IMPORT); + if (strcmp(yytext,"%echo") == 0) return(ECHO); + if (strcmp(yytext,"%new") == 0) return(NEW); + if (strcmp(yytext,"%apply") == 0) return(APPLY); + if (strcmp(yytext,"%clear") == 0) return(CLEAR); + if (strcmp(yytext,"%doconly") == 0) return(DOCONLY); + + /* Have an unknown identifier, as a last step, we'll */ + /* do a typedef lookup on it. */ + yylval.tok.text = NewString(yytext); + if (LParse_typedef_check(yylval.tok.text)) { + return TYPE_TYPEDEF; + } + return(ID); + } + return(l1); +} + +int lparse_yylex() { + int t; + t = yylex1(); + /* printf("%d\n",t); */ + return t; +} + diff --git a/Source/LParse/lparse.h b/Source/LParse/lparse.h new file mode 100644 index 000000000..f6a57f5c0 --- /dev/null +++ b/Source/LParse/lparse.h @@ -0,0 +1,98 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef _LPARSE_H +#define _LPARSE_H + +#include "swig.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +extern void LParse_push(DOH *); +extern DOH *LParse_skip_balanced(int, int); +extern void LParse_skip_semi(); +extern void LParse_skip_decl(); +extern DOH *LParse_parse(DOH *str); +extern DOH *LParse_file(); +extern int LParse_line(); +extern void LParse_set_location(DOH *file, int line); +extern void LParse_error(DOH *file, int line, char *fmt, ...); +extern void LParse_macro_location(DOH *name, DOH *file, int line); +extern int LParse_cplusplus(int i); +extern int LParse_objc(int i); + +#define LPARSE_T_INT 1 +#define LPARSE_T_SHORT 2 +#define LPARSE_T_LONG 3 +#define LPARSE_T_UINT 4 +#define LPARSE_T_USHORT 5 +#define LPARSE_T_ULONG 6 +#define LPARSE_T_UCHAR 7 +#define LPARSE_T_SCHAR 8 +#define LPARSE_T_BOOL 9 +#define LPARSE_T_DOUBLE 10 +#define LPARSE_T_FLOAT 11 +#define LPARSE_T_CHAR 12 +#define LPARSE_T_USER 13 +#define LPARSE_T_VOID 14 +#define LPARSE_T_ENUM 50 +#define LPARSE_T_STRING 51 +#define LPARSE_T_VARARGS 52 +#define LPARSE_T_FUNCTION 53 +#define LPARSE_T_SYMBOL 98 +#define LPARSE_T_ERROR 99 + +/* This is the semi-bogus type structure from SWIG1.1. It will be replaced someday */ + +#define LPARSE_MAX_NAME 96 + +typedef struct { + DOHXCOMMON; + int type; + char *name; + char is_pointer; + char implicit_ptr; + char is_reference; + char status; + char *qualifier; + char *arraystr; +} LParseType; + +extern LParseType *NewLParseType(int t); +extern void DelLParseType(DOH *t); +extern DOH *CopyLParseType(DOH *t); +extern int LParseType_check(DOH *t); +extern void LParse_typedef_add(LParseType *t, DOH *tname); +extern void LParse_typedef_resolve(LParseType *t, int level); +extern void LParse_typedef_replace(LParseType *t); +extern int LParse_typedef_check(DOH *tname); +extern void LParse_typedef_updatestatus(LParseType *t, int newstatus); +extern void LParse_merge_scope(DOH *h); +extern void LParse_new_scope(DOH *); +extern DOH *LParse_collapse_scope(DOH *prefix); + +#ifdef __cplusplus +} +#endif + +#endif + + + + + diff --git a/Source/LParse/parser.y b/Source/LParse/parser.y new file mode 100644 index 000000000..c0e04b4d6 --- /dev/null +++ b/Source/LParse/parser.y @@ -0,0 +1,2038 @@ +%{ +/******************************************************************************* + * 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. + ***********************************************************************/ + +#define yylex lparse_yylex +#define yyerror lparse_yyerror +#define yyparse lparse_yyparse +#define yylval lparse_yylval +#define yychar lparse_yychar +#define yynerrs lparse_yynerrs + +extern int lparse_yylex(); +void yyerror (char *s); + +#include "lparse.h" +#include "preprocessor.h" + +#define CPLUS_PRIVATE 1 +#define CPLUS_PUBLIC 2 + +static DOH *top = 0; +static int readonly = 0; +static DOH *swig_rename = 0; +static LParseType *Active_typedef = 0; +static LParseType *Active_type = 0; +static DOH *Active_extern = 0; +static DOH *name_hash = 0; +static int NewObject = 0; +static int cplus_mode = CPLUS_PUBLIC; +static DOH *nested = 0; +static int Intype = 0; + +/* LParse_parse() - Main entry point to the C parser */ + DOH *LParse_parse(DOH *str) { + int yyparse(); + DOH *tp; + LParse_push(str); + top = NewHash(); + nested = NewList(); + Setattr(top, "tag", "IncludeFile"); + Setattr(top,"name", Getfile(str)); + name_hash = NewHash(); + tp = top; + yyparse(); + return tp; + } + + static void add_child(DOH *o) { + DOH *child; + assert(top); + + child = Getattr(top,"children"); + if (!child) { + child = NewList(); + Setattr(top,"children", child); + } + Setattr(o,"parent", top); + Append(child,o); + } + + static void apply_modifier(DOH *o) { + DOH *n; + if (swig_rename) { + Setattr(o,"rename",swig_rename); + } + n = Getattr(name_hash,Getattr(o,"name")); + if (n) { + Setattr(o,"rename",n); + } + if (NewObject) Setattr(o,"new",DohNone); + NewObject = 0; + swig_rename = 0; + } + + static DOH *new_node(char *tag, DOH *file, int line) { + DOH *o; + o = NewHash(); + Setattr(o,"tag",tag); + Setline(o,line); + Setfile(o,file); + add_child(o); + return o; + } + + static void dump_nested(DOH *name) { + int i; + for (i = 0; i < Len(nested); i++) { + DOH *code; + LParseType *t; + DOH *o = Getitem(nested,i); + code = Getattr(o,"code"); + Replace(code,"$classname",name,DOH_REPLACE_ANY); + t = (LParseType *) Getattr(o,"type"); + sprintf(t->name,"%s_%s",Char(name),Char(Getattr(o,"name"))); + o = new_node("HeaderBlock",Getfile(code),Getline(code)); + Setattr(o,"text",code); + o = new_node("MemberData",Getfile(code),Getline(code)); + Setattr(o,"name",Getattr(o,"name")); + Setattr(o,"type",t); + Seek(code,0,SEEK_SET); + /* Printf(stderr,"NESTED : %s\n", code); */ + LParse_push(code); + } + Clear(nested); + } + +#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; + LParseType *type; + struct { + DOH *id; + int is_pointer; + int is_reference; + } decl; + struct { + DOH *name; + DOH *value; + DOH *array; + } pname; + struct { + DOH *name; + DOH *array; + DOH *parms; + } tmname; +}; + +/* Literals */ +%token ID TYPE_TYPEDEF +%token HBLOCK +%token STRING +%token NUM_INT NUM_FLOAT CHARCONST NUM_UNSIGNED NUM_LONG NUM_ULONG + +/* C Symbols */ + +%token LPAREN RPAREN LBRACE RBRACE COMMA SEMI PERIOD LBRACKET RBRACKET EQUAL COLON POUND + +/* C keywords */ +%token CONST DEFINED ENUM EXTERN SIZEOF STATIC STRUCT TYPEDEF UNION + +/* C++ keywords */ +%token CLASS FRIEND OPERATOR PRIVATE PROTECTED PUBLIC TEMPLATE THROW VIRTUAL + +/* Objective C keywords */ +%token OC_INTERFACE OC_END OC_PUBLIC OC_PRIVATE OC_PROTECTED OC_CLASS OC_IMPLEMENT OC_PROTOCOL + +/* C Types */ +%token TYPE_INT TYPE_UNSIGNED TYPE_SHORT TYPE_LONG TYPE_FLOAT TYPE_DOUBLE TYPE_CHAR TYPE_VOID TYPE_SIGNED TYPE_BOOL + +/* SWIG directives */ +%token ADDMETHODS ALPHA_MODE APPLY CHECKOUT CLEAR CONSTANT DOCONLY DOC_DISABLE DOC_ENABLE ECHO EXCEPT +%token ILLEGAL IMPORT INCLUDE INIT INLINE LOCALSTYLE MACRO MACRO MODULE NAME NATIVE NEW PRAGMA +%token RAW_MODE READONLY READWRITE RENAME SECTION STYLE SUBSECTION SUBSUBSECTION TEXT TITLE +%token TYPE TYPEMAP USERDIRECTIVE WEXTERN WRAPPER + +/* Operators */ +%left LOR +%left LAND +%left EQUALTO NOTEQUAL GREATERTHAN LESSTHAN LTEQUAL GTEQUAL +%left OR +%left XOR +%left AND +%left LSHIFT RSHIFT +%left PLUS MINUS +%left STAR SLASH +%left UMINUS NOT LNOT +%left DCOLON + +%type idstring idtype cpptype template_decl stars array array2 expr definetype def_args extern_spec func_end tm_method pragma_arg ename +%type base_specifier access_specifier cpp_end ctor_end stylearg +%type file_include_type parm parms ptail tm_tail tm_list tm_parm tm_args idlist inherit base_list stylelist styletail +%type type realtype opt_signed opt_unsigned +%type declaration nested_decl +%type pname +%type tm_name + +%% + +/* The productions of the grammar with their + associated semantic actions. */ + +interface : interface statement { } + | empty { } + ; + +statement : swig_directive { Intype = 0; } + | c_declaration { Intype = 0; } + | LBRACE { + DOH *o = new_node("Scope",$1.filename,$1.line); + top = o; + } interface RBRACE { + top = Getattr(top,"parent"); + } + | SEMI { } + | error { } + ; + +/* ============================================================================= + * -- SWIG DIRECTIVES -- + * ============================================================================= */ +swig_directive : MODULE idstring { + if (!Getattr(top,"module")) { + Setattr(top,"module",$2.text); + } + } + | MACRO idtype 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); + } + + | RENAME ID ID SEMI { Setattr(name_hash,$2.text,$3.text); } + | CONSTANT ID definetype SEMI { + DOH *o = new_node("Constant",$2.filename, $2.line); + Setattr(o,"name",$2.text); + Setattr(o,"value",$3.text); + SetInt(o,"type",$3.ivalue); + apply_modifier(o); + } + | ECHO HBLOCK { Printf(stderr,"%s\n", $2.text); } + | ECHO STRING { Printf(stderr,"%s\n", $2.text); } + | file_include + | code_block + | doc_directive + | typemap_directive + | except_directive + | pragma_directive + | modifier_directive + | native_directive + | TYPE ID idlist SEMI { + DOH *l; + LParseType *t; + int i; + Insert($3,0,$2.text); + for (i = 0; i < Len($3); i++) { + l = Getitem($3,i); + t = NewLParseType(LPARSE_T_USER); + LParse_typedef_add(t,l); + } + } + ; + +/* -- File inclusion directives -- */ + +file_include : file_include_type STRING LBRACE { + Setattr($1,"name",$2.text); + top = $1; + LParse_set_location($2.text,0); + } interface RBRACE { + top = Getattr(top,"parent"); + LParse_set_location($3.filename,$3.line + 1); + } + +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 { readonly = 1; } + | READWRITE { readonly = 0; } + | NAME LPAREN idstring RPAREN { swig_rename = Copy($3.text); } statement { swig_rename = 0; } + | NEW { NewObject = 1; } statement { NewObject = 0; } + ; + +/* -- Code inclusion directives -- */ + +code_block : HBLOCK { + DOH *o = new_node("HeaderBlock",$1.filename,$1.line); + Setattr(o,"text", $1.text); + } + | WRAPPER HBLOCK { + DOH *o = new_node("WrapperBlock",$2.filename,$2.line); + Setattr(o,"text",$2.text); + } + | INIT HBLOCK { + DOH *o = new_node("InitBlock",$2.filename,$2.line); + Setattr(o,"text",$2.text); + } + | INLINE HBLOCK { + DOH *pp; + DOH *o = new_node("HeaderBlock",$2.filename,$2.line); + Setattr(o,"text", $2.text); + Seek($2.text,0,SEEK_SET); + pp = Preprocessor_parse($2.text); + Seek(pp,0,SEEK_SET); + LParse_push(pp); + } + ; + +/* -- Documentation directives -- */ + +doc_directive : DOC_ENABLE { + new_node("DocEnable",$1.filename,$1.line); + } + | DOC_DISABLE { + new_node("DocDisable",$1.filename,$1.line); + } + +/* %title directive */ + + | TITLE STRING styletail { + DOH *o = new_node("Title",$1.filename,$1.line); + Setattr(o,"text",$2.text); + Setattr(o,"parms",$3); + } + +/* %section directive */ + + | SECTION STRING styletail { + DOH *o = new_node("Section",$1.filename,$1.line); + Setattr(o,"text",$1.text); + Setattr(o,"parms",$3); + } + +/* %subsection directive */ + | SUBSECTION STRING styletail { + DOH *o = new_node("SubSection",$1.filename,$1.line); + Setattr(o,"text",$1.text); + Setattr(o,"parms",$3); + } + +/* %subsubsection directive */ + | SUBSUBSECTION STRING styletail { + DOH *o = new_node("SubSubSection",$1.filename,$1.line); + Setattr(o,"text",$1.text); + Setattr(o,"parms",$3); + } + +/* %text directive */ + + | TEXT HBLOCK { + DOH *o = new_node("Text",$1.filename,$1.line); + Setattr(o,"text",$2.text); + } + +/* Disable code generation */ + | DOCONLY { } + + +/* %style directive. This applies to all current styles */ + + | STYLE stylelist { + DOH *o = new_node("Style",$1.filename,$1.line); + Setattr(o,"parms",$2); + } + +/* %localstyle directive. This applies only to the current style */ + + | LOCALSTYLE stylelist { + DOH *o = new_node("LocalStyle",$1.filename,$1.line); + Setattr(o,"parms",$2); + } + +/* Documentation style list */ + +stylelist : ID stylearg styletail { + DOH *o; + o = NewHash(); + Setattr(o,"name",$1.text); + Setattr(o,"value",$2.text); + Insert($3,0,o); + $$ = $3; + } + ; + +styletail : styletail COMMA ID stylearg { + DOH *o; + $$ = $1; + o = NewHash(); + Setattr(o,"name",$3.text); + Setattr(o,"value",$4.text); + } + | empty { + $$ = NewList(); + } + ; + +stylearg : EQUAL NUM_INT { + $$ = $2; + } + | EQUAL STRING { + $$ = $2; + } + | empty { + $$.text = 0; + } + ; + +idstring : ID { $$ = $1; } + | TYPE_TYPEDEF { $$ = $1; } + | STRING { $$ = $1; } + ; + +/* -- Typemap directives -- */ + + +typemap_directive: TYPEMAP LPAREN idtype COMMA tm_method RPAREN tm_list LBRACE { + DOH *o, *t, *l; + int i; + t = LParse_skip_balanced('{','}'); + 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,"name",Getattr(l,"name")); + Setattr(o,"type",Getattr(l,"type")); + Setattr(o,"parms",Getattr(l,"parms")); + } + } + +/* Create a new typemap in current language */ + | TYPEMAP LPAREN tm_method RPAREN tm_list LBRACE { + DOH *o, *t, *l; + int i; + t = LParse_skip_balanced('{','}'); + 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,"name",Getattr(l,"name")); + Setattr(o,"type",Getattr(l,"type")); + Setattr(o,"parms",Getattr(l,"parms")); + } + } + +/* Clear a typemap */ + + | TYPEMAP LPAREN idtype COMMA tm_method RPAREN tm_list SEMI { + DOH *o, *l; + int i; + for (i = 0; i < Len($7); i++) { + l = Getitem($7,i); + o = new_node("TypemapClear",$1.filename, $1.line); + Setattr(o,"lang",$3.text); + Setattr(o,"method",$5.text); + Setattr(o,"name",Getattr(l,"name")); + Setattr(o,"type",Getattr(l,"type")); + } + } + +/* Clear a typemap in current language */ + + | TYPEMAP LPAREN tm_method RPAREN tm_list SEMI { + DOH *o, *l; + int i; + for (i = 0; i < Len($5); i++) { + l = Getitem($5,i); + o = new_node("TypemapClear",$1.filename, $1.line); + Setattr(o,"method",$3.text); + Setattr(o,"name",Getattr(l,"name")); + Setattr(o,"type",Getattr(l,"type")); + } + } + +/* Copy a typemap */ + + | TYPEMAP LPAREN idtype COMMA tm_method RPAREN tm_list EQUAL tm_parm SEMI { + DOH *o, *l; + int i; + 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,"name", Getattr(l,"name")); + Setattr(o,"type", Getattr(l,"type")); + Setattr(o,"parms",Getattr(l,"parms")); + Setattr(o,"srcname",Getattr($9,"name")); + Setattr(o,"srctype",Getattr($9,"type")); + } + } + +/* Copy typemap in current language */ + + | TYPEMAP LPAREN tm_method RPAREN tm_list EQUAL tm_parm SEMI { + DOH *o, *l; + int i; + 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,"name", Getattr(l,"name")); + Setattr(o,"type", Getattr(l,"type")); + Setattr(o,"parms",Getattr(l,"parms")); + Setattr(o,"srcname",Getattr($7,"name")); + Setattr(o,"srctype",Getattr($7,"type")); + } + } + +/* Apply directive */ + + | APPLY tm_parm LBRACE tm_list RBRACE { + DOH *o; + o = new_node("Apply",$1.filename, $1.line); + Setattr(o,"name",Getattr($2,"name")); + Setattr(o,"type",Getattr($2,"type")); + Setattr(o,"parms",$4); + } + +/* Clear directive */ + + | CLEAR tm_list SEMI { + DOH *o; + o = new_node("ClearApply",$1.filename, $1.line); + Setattr(o,"parms",$2); + } + ; + +tm_method : idtype { + $$ = $1; + } + | CONST { + $$.text = NewString("const"); + } + ; + + +tm_list : tm_parm tm_tail { + Append($2,$1); + $$ = $2; + } + ; + +tm_tail : COMMA tm_parm tm_tail { + Append($2,$3); + $$ = $3; + } + | empty { $$ = NewList(); } + ; + +tm_parm : type tm_name { + $$ = NewHash(); + if ($2.array) { + $1->is_pointer++; + $1->arraystr = copy_string(Char($2.array)); + } + Setattr($$,"type",$1); + if ($2.name) + Setattr($$,"name",$2.name); + if ($2.parms) + Setattr($$,"parms",$2.parms); + } + | type stars tm_name { + $$ = NewHash(); + $1->is_pointer += $2.ivalue; + if ($3.array) { + $1->is_pointer++; + $1->arraystr = copy_string(Char($3.array)); + } + Setattr($$,"type",$1); + if ($3.name) + Setattr($$,"name",$3.name); + if ($3.parms) + Setattr($$,"parms",$3.parms); + } + | type AND tm_name { + $$ = NewHash(); + $1->is_reference = 1; + $1->is_pointer++; + if ($3.array) { + $1->is_pointer++; + $1->arraystr = copy_string(Char($3.array)); + } + Setattr($$,"type",$1); + if ($3.name) + Setattr($$,"name",$3.name); + if ($3.parms) + Setattr($$,"parms",$3.parms); + } + ; + +tm_name : ID tm_args { + $$.parms = $2; + $$.name = $1.text; + $$.array = 0; + } + | ID array tm_args { + $$.name = $1.text; + $$.array = $2.text; + $$.parms = $3; + } + | array tm_args { + $$.name = 0; + $$.array = $1.text; + $$.parms = $2; + } + | tm_args { + $$.name = 0; + $$.array = 0; + $$.parms = $1; + } + ; + +tm_args : LPAREN parms RPAREN { + $$ = $2; + } + | empty { + $$ = 0; + } + ; + + +/* -- Exceptions -- */ + +except_directive: EXCEPT LPAREN idtype RPAREN LBRACE { + DOH *o, *t; + t = LParse_skip_balanced('{','}'); + o = new_node("Exception",$1.filename,$1.line); + Setattr(o,"lang",$3.text); + Setattr(o,"code",t); + } + +/* A Generic Exception (no language specified */ + | EXCEPT LBRACE { + DOH *o, *t; + t = LParse_skip_balanced('{','}'); + o = new_node("Exception",$1.filename,$1.line); + Setattr(o,"code",t); + } + +/* Clear an exception */ + | EXCEPT LPAREN idtype RPAREN SEMI { + DOH *o; + o = new_node("ExceptionClear",$1.filename,$1.line); + Setattr(o,"lang",$3.text); + } + +/* Generic clear */ + | EXCEPT SEMI { + new_node("ExceptionClear",$1.filename,$1.line); + } + ; + + +pragma_directive : PRAGMA ID pragma_arg SEMI { + DOH *o = new_node("Pragma",$1.filename,$1.line); + Setattr(o,"name",$2.text); + Setattr(o,"value",$3.text); + } + | PRAGMA LPAREN ID RPAREN ID pragma_arg SEMI { + DOH *o = new_node("Pragma",$1.filename,$1.line); + Setattr(o,"name",$5.text); + Setattr(o,"lang",$3.text); + Setattr(o,"value",$6.text); + } + ; + +pragma_arg : EQUAL definetype { + $$.text = $2.text; + } + | empty { + $$.text = 0; + } + ; + + +/* A native wrapper function */ + +native_directive : NATIVE LBRACE { + DOH *o = new_node("Native",$1.filename,$1.line); + top = o; + } interface RBRACE { + top = Getattr(top,"parent"); + } + ; + +/* ============================================================================= + * -- C Declarations -- + * ============================================================================= */ + +c_declaration : variable_decl + | function_decl + | enum_decl + | typedef_decl + | cpp_decl + | STATIC { LParse_skip_decl(); } + ; + +/* A variable declaration */ + +variable_decl : extern_spec type declaration array2 def_args { + DOH *o; + Active_type = (LParseType *) Copy($2); + Active_extern = $1.text; + $2->is_pointer += $3.is_pointer; + if ($4.text) { + $2->is_pointer++; + $2->arraystr = copy_string(Char($4.text)); + } + $2->is_reference = $3.is_reference; + o = new_node("Variable", Getfile($3.id),Getline($3.id)); + Setattr(o,"name",$3.id); + Setattr(o,"type",$2); + if ($1.ivalue) { + Setattr(o,"extern",$1.text); + } + if ($5.text) + Setattr(o,"value",$5.text); + if (readonly) + Setattr(o,"readonly",DohNone); + + apply_modifier(o); + } stail { } + +/* Global variable that smells like a function pointer */ + + | extern_spec type LPAREN STAR { + LParse_error($3.filename,$3.line,"Pointer to function not currently supported.\n"); + LParse_skip_decl(); + } + ; + + +/* A function declaration */ + +function_decl : extern_spec type declaration LPAREN parms RPAREN cpp_const { + DOH *o; + Active_type = (LParseType *) Copy($2); + Active_extern = $1.text; + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + o = new_node("Function",Getfile($3.id),Getline($3.id)); + Setattr(o,"name",$3.id); + Setattr(o,"type",$2); + Setattr(o,"parms",$5); + if ($1.ivalue) { + Setattr(o,"extern", $1.text); + } + apply_modifier(o); + } stail { } + +/* A function declaration with code after it */ + + | extern_spec type declaration LPAREN parms RPAREN func_end { + DOH *o; + Active_type = (LParseType *) Copy($2); + Active_extern = $1.text; + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + o = new_node("Function",Getfile($3.id),Getline($3.id)); + Setattr(o,"name",$3.id); + Setattr(o,"type",$2); + Setattr(o,"parms",$5); + if ($1.ivalue) { + Setattr(o,"extern", $1.text); + } + if ($7.text) + Setattr(o,"code",$7.text); + apply_modifier(o); + }; + +/* A function declared without any return datatype */ + + | extern_spec declaration LPAREN parms RPAREN cpp_const { + DOH *o; + LParseType *t = NewLParseType(LPARSE_T_INT); + Active_type = (LParseType *) Copy(t); + Active_extern = $1.text; + t->is_pointer += $2.is_pointer; + t->is_reference = $2.is_reference; + o = new_node("Function", Getfile($2.id),Getline($2.id)); + Setattr(o,"name",$2.id); + Setattr(o,"type",t); + Setattr(o,"parms",$4); + if ($1.ivalue) { + Setattr(o,"extern", $1.text); + } + apply_modifier(o); + } stail { }; + +/* A function with an explicit inline directive. Not safe to use inside a %inline block */ + + | INLINE type declaration LPAREN parms RPAREN func_end { + DOH *o; + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + o = new_node("Function",Getfile($3.id),Getline($3.id)); + Setattr(o,"name",$3.id); + Setattr(o,"type",$2); + Setattr(o,"parms",$5); + Setattr(o,"inline",NewString("")); + if ($7.text) { + Setattr(o,"code",$7.text); + } + apply_modifier(o); + } + ; + +/* Allow lists of variables and functions to be built up */ + +stail : SEMI { } + | COMMA declaration array2 def_args { + DOH *o; + LParseType *t = (LParseType *) Copy(Active_type); + t->is_pointer += $2.is_pointer; + if ($3.text > 0) { + t->is_pointer++; + t->arraystr = copy_string(Char($3.text)); + } + t->is_reference = $2.is_reference; + o = new_node("Variable", Getfile($2.id),Getline($2.id)); + Setattr(o,"name",$2.id); + Setattr(o,"type",t); + if (Active_extern) { + Setattr(o,"extern",Active_extern); + } + if ($4.text) + Setattr(o,"value",$4.text); + apply_modifier(o); + if (readonly) + Setattr(o,"readonly",DohNone); + } stail { } + | COMMA declaration LPAREN parms RPAREN { + DOH *o; + LParseType *t = (LParseType *) Copy(Active_type); + t->is_pointer += $2.is_pointer; + t->is_reference = $2.is_reference; + o = new_node("Function", Getfile($2.id), Getline($2.id)); + Setattr(o,"name",$2.id); + Setattr(o,"parms",$4); + Setattr(o,"type", t); + if (Active_extern) { + Setattr(o,"extern",Active_extern); + } + apply_modifier(o); + } stail { } + ; + +extern_spec : EXTERN { + $$.ivalue = 1; + $$.text = NewString(""); + } + | EXTERN STRING { + $$.ivalue = 1; + $$.text = $2.text; + } + | empty { + $$.ivalue = 0; + $$.text = 0; + } + ; + +func_end : cpp_const LBRACE { $$.text = LParse_skip_balanced('{','}'); } + ; + +cpp_const : CONST {} + | THROW LPAREN { LParse_skip_balanced('(',')'); } + | empty {} + ; + +/* Enumerations */ + +enum_decl : extern_spec ENUM ename LBRACE { + DOH *o; + o = new_node("Enumeration",$2.filename,$2.line); + Setattr(o,"name",$2.text); + top = o; + } enumlist RBRACE SEMI { + LParseType *t; + top = Getattr(top,"parent"); + t = NewLParseType(LPARSE_T_ENUM); + LParse_typedef_add(t,$3.text); + } + +/* A typdef'd enum. Pretty common in C headers */ + + | TYPEDEF ENUM ename LBRACE { + DOH *o; + o = new_node("Enumeration",$2.filename,$2.line); + Setattr(o,"name",$3.text); + top = o; + } enumlist RBRACE ID { + LParseType *t; + DOH *o2; + top = Getattr(top,"parent"); + t = NewLParseType(LPARSE_T_ENUM); + Active_typedef = (LParseType *) Copy(t); + LParse_typedef_add(t,$3.text); + LParse_typedef_add(t,$8.text); + o2 = new_node("Typedef",$1.filename,$1.line); + Setattr(o2,"name",$8.text); + Setattr(o2,"type",Copy(t)); + } typedeflist SEMI { } + ; + +/* Some stuff for handling enums */ + +ename : ID { $$ = $1; } + | empty { $$.text = NewString(""); } + ; + +enumlist : enumlist COMMA edecl {} + | edecl {} + ; + +edecl : ID { + DOH *o = new_node("EnumValue",$1.filename,$1.line); + Setattr(o,"name",$1.text); + Setattr(o,"value",$1.text); + } + | ID EQUAL expr { + DOH *o = new_node("EnumValue",$1.filename,$1.line); + Setattr(o,"name",$1.text); + Setattr(o,"value",$1.text); + } + | empty { } + ; + +typedef_decl : TYPEDEF type declaration { + DOH *o; + Active_typedef = (LParseType *) Copy($2); + $2->is_pointer += $3.is_pointer; + LParse_typedef_add($2,$3.id); + o = new_node("Typedef", $1.filename, $1.line); + Setattr(o,"name", $3.id); + Setattr(o,"type", Copy($2)); + } typedeflist SEMI { }; + +/* A rudimentary typedef involving function pointers */ + + | TYPEDEF type LPAREN STAR pname RPAREN LPAREN parms RPAREN SEMI { + DOH *o; + LParseType *rt; + rt = NewLParseType(LPARSE_T_FUNCTION); + rt->is_pointer = 1; + strcpy(rt->name,""); + LParse_typedef_add(rt,$5.name); + o = new_node("Typedef", $1.filename, $1.line); + Setattr(o,"name", $5.name); + Setattr(o,"type", Copy(rt)); + Setattr(o,"rettype",$2); + Setattr(o,"parms", $8); + } + +/* A typedef involving function pointers again */ + + | TYPEDEF type stars LPAREN STAR pname RPAREN LPAREN parms RPAREN SEMI { + DOH *o; + LParseType *rt; + rt = NewLParseType(LPARSE_T_FUNCTION); + rt->is_pointer = 1; + strcpy(rt->name,""); + $2->is_pointer += $3.ivalue; + LParse_typedef_add(rt,$6.name); + o = new_node("Typedef", $1.filename, $1.line); + Setattr(o,"name", $6.name); + Setattr(o,"type", Copy(rt)); + Setattr(o,"parms", $9); + Setattr(o,"rettype", $2); + } + +/* A typedef involving arrays */ + + | TYPEDEF type declaration array { + DOH *o; + Active_typedef = (LParseType *) Copy($2); + $2->is_pointer += $3.is_pointer; + $2->is_pointer++; + $2->arraystr = copy_string(Char($4.text)); + LParse_typedef_add($2,$3.id); + o = new_node("Typedef", $1.filename, $1.line); + Setattr(o,"name", $3.id); + Setattr(o,"type", Copy($2)); + } typedeflist SEMI { } + ; + +typedeflist : COMMA declaration typedeflist { + if (Active_typedef) { + DOH *o; + LParseType *t; + t = (LParseType *) Copy(Active_typedef); + t->is_pointer += $2.is_pointer; + LParse_typedef_add(t,$2.id); + o = new_node("Typedef", Getfile($2.id), Getline($2.id)); + Setattr(o,"name", $2.id); + Setattr(o,"type", t); + } + } + | COMMA declaration array { + DOH *o; + LParseType *t; + t = (LParseType *) Copy(Active_typedef); + t->is_pointer += $2.is_pointer + 1; + t->arraystr = copy_string(Char($3.text)); + LParse_typedef_add(t,$2.id); + o = new_node("Typedef", Getfile($2.id), Getline($2.id)); + Setattr(o,"name", $2.id); + Setattr(o,"type", t); + } + | empty + ; + + +/* ============================================================================= + * -- Feeble C++ (yuck) Parsing -- + * ============================================================================= */ + +cpp_decl : cpp_class { } + | cpp_other { } + ; + +cpp_class : extern_spec cpptype ID inherit LBRACE { + LParseType *t; + DOH *o = new_node("Class",$3.filename,$3.line); + Setattr(o,"name",$3.text); + Setattr(o,"bases",$4); + Setattr(o,"type",$2.text); + apply_modifier(o); + t = NewLParseType(LPARSE_T_USER); + strcpy(t->name,Char($3.text)); + LParse_typedef_add(t,$3.text); + LParse_new_scope(0); + if (Cmp($2.text,"class") == 0) { + cplus_mode = CPLUS_PRIVATE; + } else { + cplus_mode = CPLUS_PUBLIC; + } + top = o; + } cpp_members RBRACE { + dump_nested($3.text); + Setattr(top,"scope",LParse_collapse_scope($3.text)); + top = Getattr(top,"parent"); + cplus_mode = CPLUS_PUBLIC; + } + +/* Class with a typedef */ + + | TYPEDEF cpptype ID inherit LBRACE { + LParseType *t; + DOH *o = new_node("Class",$3.filename,$3.line); + Setattr(o,"name",$3.text); + Setattr(o,"bases",$4); + Setattr(o,"type",$2.text); + apply_modifier(o); + t = NewLParseType(LPARSE_T_USER); + strcpy(t->name,Char($3.text)); + LParse_typedef_add(t,$3.text); + LParse_new_scope(0); + if (Cmp($2.text,"class") == 0) { + cplus_mode = CPLUS_PRIVATE; + } else { + cplus_mode = CPLUS_PUBLIC; + } + top = o; + } cpp_members RBRACE declaration { + DOH *o2; + Active_typedef = NewLParseType(LPARSE_T_USER); + sprintf(Active_typedef->name,"%s %s", Char($2.text),Char($3.text)); + Active_typedef->is_pointer = 0; + Active_typedef->implicit_ptr = 0; + /* Create dump nested class code */ + if ($9.is_pointer > 0) { + dump_nested($3.text); + } else { + dump_nested($9.id); + } + Setattr(top,"scope",LParse_collapse_scope($3.text)); + o2 = top; + top = Getattr(top,"parent"); + /* Create a typedef in global scope */ + if ($9.is_pointer == 0) { + LParse_typedef_add((LParseType *) Copy(Active_typedef), $9.id); + Setattr(o2,"typedef",$9.id); + } else { + LParseType *t = (LParseType *) Copy(Active_typedef); + t->is_pointer += $9.is_pointer; + LParse_typedef_add(t,$9.id); + } + cplus_mode = CPLUS_PUBLIC; + } typedeflist { }; + +/* An unnamed struct with a typedef */ + + | TYPEDEF cpptype LBRACE { + DOH *o = new_node("Class",$1.filename,$1.line); + Setattr(o,"type",$2.text); + LParse_new_scope(0); + if (Cmp($2.text,"class") == 0) { + cplus_mode = CPLUS_PRIVATE; + } else { + cplus_mode = CPLUS_PUBLIC; + } + top = o; + } cpp_members RBRACE declaration { + if ($7.is_pointer > 0) { + LParse_error($1.filename,$1.line,"typedef %s {} *%s not supported correctly. Will be ignored.\n", $2.text, $7.id); + Setattr(top,"error",DohNone); + top = Getattr(top,"parent"); + } else { + /* Create a datatype for correctly processing the typedef */ + Active_typedef = NewLParseType(LPARSE_T_USER); + sprintf(Active_typedef->name,"%s",Char($7.id)); + if ($7.is_pointer == 0) { + dump_nested($7.id); + } + Setattr(top,"name",$7.id); + apply_modifier(top); + Setattr(top,"typedef",$7.id); + Setattr(top,"scope",LParse_collapse_scope(0)); + top = Getattr(top,"parent"); + LParse_typedef_add((LParseType *) Copy(Active_typedef),$7.id); + } + cplus_mode = CPLUS_PUBLIC; + } typedeflist { } + ; + +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 : idtype { + LParse_error($1.filename,$1.line,"No access specifier given for base class %s (ignored).\n", $1.text); + $$.text = 0; + } + | VIRTUAL ID { + LParse_error($2.filename,$2.line,"No access specifier given for base class %s (ignored).\n", $2.text); + $$.text = 0; + } + | VIRTUAL access_specifier ID { + if (Cmp($2.text,"public") == 0) { + $$ = $3; + } else { + LParse_error($3.filename,$3.line,"%s inheritance not supported (ignored).\n", $2.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 VIRTUAL ID { + if (Cmp($1.text,"public") == 0) { + $$ = $3; + } else { + $$.text = 0; + LParse_error($3.filename,$3.line,"%s inheritance not supported (ignored).\n", $1.text); + } + } + ; + +access_specifier : PUBLIC { $$.text = NewString("public"); } + | PRIVATE { $$.text = NewString("private"); } + | PROTECTED { $$.text = NewString("protected"); } + ; + +cpp_members : cpp_member cpp_members {} + | ADDMETHODS LBRACE { + DOH *o = new_node("AddMethods",$1.filename,$1.line); + top = o; + } cpp_members RBRACE { + top = Getattr(top,"parent"); + } cpp_members { } + | error { + LParse_error(0,0,"Syntax error in class definition.\n"); + LParse_skip_decl(); + } cpp_members { } + | empty { } + ; + +cpp_member : type declaration LPAREN parms RPAREN cpp_end { + if (cplus_mode == CPLUS_PUBLIC) { + DOH *o = new_node("MemberFunction",$3.filename,$3.line); + Setattr(o,"name",$2.id); + $1->is_pointer += $2.is_pointer; + $1->is_reference = $2.is_reference; + Setattr(o,"type",$1); + Setattr(o,"parms",$4); + Setattr(o,"code",$6.text); + apply_modifier(o); + } + } + + | VIRTUAL type declaration LPAREN parms RPAREN cpp_end { + if (cplus_mode == CPLUS_PUBLIC) { + DOH *o = new_node("MemberFunction",$4.filename,$4.line); + Setattr(o,"name",$3.id); + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + Setattr(o,"type",$2); + Setattr(o,"parms",$5); + Setattr(o,"code",$7.text); + apply_modifier(o); + } + } + +/* Possibly a constructor */ + | idtype LPAREN parms RPAREN ctor_end { + if (cplus_mode == CPLUS_PUBLIC) { + DOH *o = new_node("Constructor", $2.filename, $2.line); + Setattr(o,"name",$1.text); + Setattr(o,"parms",$3); + Setattr(o,"code",$5.text); + apply_modifier(o); + } + } + +/* A destructor (hopefully) */ + + | NOT idtype LPAREN parms RPAREN cpp_end { + if (cplus_mode == CPLUS_PUBLIC) { + DOH *o = new_node("Destructor",$2.filename,$2.line); + Setattr(o,"name",$1.text); + Setattr(o,"parms",$4); + Setattr(o,"code",$6.text); + apply_modifier(o); + } + } + + | VIRTUAL NOT idtype LPAREN parms RPAREN cpp_end { + if (cplus_mode == CPLUS_PUBLIC) { + DOH *o = new_node("Destructor",$3.filename,$3.line); + Setattr(o,"name",$2.text); + Setattr(o,"parms",$5); + Setattr(o,"code",$7.text); + apply_modifier(o); + } + } + +/* Member data */ + + | type declaration def_args { + if (cplus_mode == CPLUS_PUBLIC) { + DOH *o = new_node("MemberData",Getfile($2.id),Getline($2.id)); + Active_type = (LParseType *) Copy($1); + $1->is_pointer += $2.is_pointer; + $1->is_reference = $2.is_reference; + Setattr(o,"name",$2.id); + Setattr(o,"type",$1); + Setattr(o,"value",$3.text); + apply_modifier(o); + } + } cpp_tail { } + + | type declaration array def_args { + if (cplus_mode == CPLUS_PUBLIC) { + DOH *o = new_node("MemberData",Getfile($2.id),Getline($2.id)); + Active_type = (LParseType *) Copy($1); + $1->is_pointer += $2.is_pointer; + $1->is_reference = $2.is_reference; + if ($3.text) { + $1->arraystr = copy_string(Char($3.text)); + $1->is_pointer++; + } + Setattr(o,"name",$2.id); + Setattr(o,"type",$1); + Setattr(o,"value",$3.text); + apply_modifier(o); + } + } + +/* Static Member data */ + + | STATIC type declaration { + if (cplus_mode == CPLUS_PUBLIC) { + DOH *o; + Active_type = (LParseType *) Copy($2); + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + o = new_node("StaticMemberData",$1.filename, $1.line); + Setattr(o,"name",$3.id); + Setattr(o,"type",$2); + apply_modifier(o); + } + } cpp_tail { } + +/* Static member function */ + + | STATIC type declaration LPAREN parms RPAREN cpp_end { + if (cplus_mode == CPLUS_PUBLIC) { + DOH *o = new_node("StaticMemberFunction",$1.filename,$1.line); + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + Setattr(o,"name",$3.id); + apply_modifier(o); + Setattr(o,"type",$2); + Setattr(o,"parms",$5); + Setattr(o,"code",$7.text); + } + } + +/* Turn on public: mode */ + + | PUBLIC COLON { cplus_mode = CPLUS_PUBLIC; } + +/* Turn on private: mode */ + + | PRIVATE COLON { cplus_mode = CPLUS_PRIVATE; } + +/* Turn on protected mode */ + + | PROTECTED COLON { cplus_mode = CPLUS_PRIVATE; } + + | modifier_directive { } + + | ENUM ename LBRACE { + DOH *o; + o = new_node("Enumeration",$2.filename,$2.line); + Setattr(o,"name",$2.text); + top = o; + } enumlist RBRACE SEMI { + LParseType *t; + top = Getattr(top,"parent"); + t = NewLParseType(LPARSE_T_ENUM); + LParse_typedef_add(t,$3.text); + } + +/* A friend : Illegal */ + | FRIEND { + LParse_skip_decl(); + } + +/* An operator: Illegal */ + | type type_extra OPERATOR { + LParse_skip_decl(); + } + +/* A typedef inside a class */ + | typedef_decl { } + +/* Pragma directive */ + + | pragma_directive { } + +/* ---------------------------------------------------------------------- + Nested structure. 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. + + 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 { + $3.text = LParse_skip_balanced('{','}'); + } nested_decl SEMI { + if (cplus_mode == CPLUS_PUBLIC) { + LParseType *t = NewLParseType(LPARSE_T_USER); + strcpy(t->name,Char($2.text)); + LParse_typedef_add(t,$2.text); + if ($5.id) { + if (Cmp($1.text,"class") == 0) { + LParse_error($2.filename,$2.line,"Nested classes not currently supported (ignored).\n"); + /* Generate some code for a new class */ + } else { + DOH *s; + DOH *n = NewHash(); + s = NewString(""); + Printf(s,"typedef %s %s $classname_%s;\n", $1.text,$3.text,$5.id); + Setattr(n,"code",s); + Setattr(n,"name",$5.id); + t = (LParseType *) Copy(t); + t->is_pointer = $5.is_pointer; + t->is_reference = $5.is_reference; + Setattr(n,"type",t); + Append(nested,n); + } + } + } + } +/* An unnamed structure definition */ + | cpptype LBRACE { + $2.text = LParse_skip_balanced('{','}'); + } declaration SEMI { + if (cplus_mode == CPLUS_PUBLIC) { + if ($4.id) { + if (Cmp($1.text,"class") == 0) { + LParse_error($2.filename,$2.line, "Nested classes not currently supported (ignored).\n"); + /* Generate some code for a new class */ + } else { + DOH *s; + LParseType *t; + DOH *n = NewHash(); + s = NewString(""); + Printf(s,"typedef %s %s $classname_%s;\n", $1.text,$2.text,$4.id); + Setattr(n,"code",s); + Setattr(n,"name",$4.id); + t = NewLParseType(LPARSE_T_USER); + t->is_pointer = $4.is_pointer; + t->is_reference = $4.is_reference; + Setattr(n,"type",t); + Append(nested,n); + } + } + } + } + ; + +nested_decl : declaration { $$ = $1;} + | empty { $$.id = 0; } + ; + +cpp_tail : SEMI { } + | COMMA declaration def_args { + if (cplus_mode == CPLUS_PUBLIC) { + DOH *o = new_node("MemberData",$1.filename,$1.line); + LParseType *t = (LParseType *) Copy(Active_type); + t->is_pointer += $2.is_pointer; + t->is_reference = $2.is_reference; + Setattr(o,"name", $2.id); + Setattr(o,"type",t); + Setattr(o,"value",$3.text); + apply_modifier(o); + } + } cpp_tail { } + | COMMA declaration array def_args { + if (cplus_mode == CPLUS_PUBLIC) { + DOH *o = new_node("MemberData",$1.filename,$1.line); + LParseType *t = (LParseType *) Copy(Active_type); + t->is_pointer += $2.is_pointer; + t->is_reference = $2.is_reference; + if ($3.text) { + t->arraystr = copy_string(Char($3.text)); + t->is_pointer++; + } + Setattr(o,"name",$2.id); + Setattr(o,"type",t); + Setattr(o,"value",$3.text); + apply_modifier(o); + } + } cpp_tail { } + ; + +cpp_end : cpp_const SEMI { + $$.text = 0; + } + | cpp_const LBRACE { + $$.text = LParse_skip_balanced('{','}'); + } + ; + +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 */ + + extern_spec cpptype idtype SEMI { + DOH *o = new_node("ClassDecl",$4.filename,$4.line); + Setattr(o,"name",$3.text); + } + +/* Any sort of out-of-class C++ declaration */ + + | extern_spec type declaration DCOLON { + LParse_skip_decl(); + } + +/* Template catch */ + | TEMPLATE { + LParse_skip_decl(); + } + +/* %addmethods directive used outside of a class definition */ + + | ADDMETHODS idtype LBRACE { + DOH *o = new_node("AddMethods",$3.filename, $3.line); + Setattr(o,"name",$2.text); + cplus_mode = CPLUS_PUBLIC; + top = o; + } cpp_members RBRACE { + top = Getattr(top,"parent"); + } + ; + +/* ============================================================================= + * -- Generic (admittedly poor) C Parsing -- + * ============================================================================= */ + +/* -- Function parameter lists -- */ + +parms : parm ptail { + Insert($2,0,$1); + $$ = $2; + } + | empty { $$ = NewList(); } + ; + +ptail : COMMA parm ptail { + Insert($3,0,$2); + $$ = $3; + } + | empty { $$ = NewList(); } + ; + +parm : type pname { + $$ = NewHash(); + Setattr($$,"name",$2.name); + if ($2.array) { + $1->is_pointer++; + $1->arraystr = copy_string(Char($2.array)); + } + if ($2.value) + Setattr($$,"value",$2.value); + Setattr($$,"type",$1); + } + | type stars pname { + $$ = NewHash(); + Setattr($$,"name",$3.name); + $1->is_pointer += $2.ivalue; + if ($3.array) { + $1->is_pointer++; + $1->arraystr = copy_string(Char($3.array)); + } + if ($3.value) { + Setattr($$,"value",$3.value); + } + Setattr($$,"type",$1); + } + | type AND pname { + $$ = NewHash(); + $1->is_reference = 1; + $1->is_pointer++; + Setattr($$,"name",$3.name); + if ($3.array) { + $1->is_pointer++; + $1->arraystr = copy_string(Char($3.array)); + } + if ($3.value) { + Setattr($$,"value",$3.value); + } + Setattr($$,"type",$1); + } + | type LPAREN stars pname RPAREN LPAREN parms RPAREN { + $$ = NewHash(); + $1->type = LPARSE_T_FUNCTION; + $1->is_pointer += $3.ivalue; + strcpy($1->name,""); + Setattr($$,"name",$4.name); + if ($4.value) + Setattr($$,"value",$4.value); + Setattr($$,"type",$1); + } + | PERIOD PERIOD PERIOD { + LParseType *t; + $$ = NewHash(); + Setattr($$,"name","..."); + t = NewLParseType(LPARSE_T_VARARGS); + Setattr($$,"type",t); + } + ; + +pname : ID def_args { + $$.name = $1.text; + $$.value = $2.text; + $$.array = 0; + } + | ID array { + $$.name = $1.text; + $$.value = 0; + $$.array = $2.text; + } + | array { + $$.name = NewString(""); + $$.value = 0; + $$.array = $1.text; + } + | 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; + } + | empty { + $$.text = 0; + $$.ivalue = 0; + } + ; + +/* Declaration must be an identifier, possibly preceded by a * for pointer types */ + +declaration : ID { $$.id = $1.text; + $$.is_pointer = 0; + $$.is_reference = 0; + } + | stars ID { + $$.id = $2.text; + $$.is_pointer = $1.ivalue; + $$.is_reference = 0; + } + | AND ID { + $$.id = $2.text; + $$.is_pointer = 1; + $$.is_reference = 1; + } + ; + +stars : STAR empty { $$.ivalue = 1; } + | STAR stars { $$.ivalue = $2.ivalue + 1;} + ; + +array : LBRACKET RBRACKET array2 { + $$.ivalue = $3.ivalue + 1; + $$.text = NewString("[]"); + Append($$.text,$3.text); + } + | LBRACKET expr RBRACKET array2 { + $$.ivalue = $4.ivalue + 1; + $$.text = NewString(""); + Printf($$.text,"[%s]",$2.text); + } + ; +array2 : array { + $$ = $1; + } + | empty { $$.ivalue = 0; + $$.text = 0; + } + ; + +type : realtype { Intype++; } + ; + +realtype : TYPE_INT { $$ = NewLParseType(LPARSE_T_INT); } + | TYPE_SHORT opt_int { $$ = NewLParseType(LPARSE_T_SHORT); } + | TYPE_LONG opt_int { $$ = NewLParseType(LPARSE_T_LONG); } + | TYPE_CHAR { $$ = NewLParseType(LPARSE_T_CHAR); } + | TYPE_BOOL { $$ = NewLParseType(LPARSE_T_BOOL); } + | TYPE_FLOAT { $$ = NewLParseType(LPARSE_T_FLOAT); } + | TYPE_DOUBLE { $$ = NewLParseType(LPARSE_T_DOUBLE); } + | TYPE_VOID { $$ = NewLParseType(LPARSE_T_VOID); } + | TYPE_SIGNED opt_signed { + if ($2) $$ = $2; + else { + $$ = NewLParseType(LPARSE_T_INT); + strcpy($$->name,"signed"); + } + } + | TYPE_UNSIGNED opt_unsigned { + if ($2) $$ = $2; + else { + $$ = NewLParseType(LPARSE_T_UINT); + strcpy($$->name,"unsigned"); + } + } + | TYPE_TYPEDEF { + $$ = NewLParseType(LPARSE_T_USER); + strcpy($$->name,Char($1.text)); + LParse_typedef_resolve($$,0); + } + | TYPE_TYPEDEF template_decl { + $$ = NewLParseType(LPARSE_T_USER); + if ($2.text) + sprintf($$->name,"%s%s",Char($1.text),Char($2.text)); + else + strcpy($$->name,Char($1.text)); + } + | CONST type { + $$ = $2; + $$->qualifier = copy_string("const"); + } + | cpptype idtype { + $$ = NewLParseType(LPARSE_T_USER); + sprintf($$->name,"%s %s",Char($1.text), Char($2.text)); + } + | TYPE_TYPEDEF DCOLON idtype { + $$ = NewLParseType(LPARSE_T_USER); + sprintf($$->name,"%s::%s",Char($1.text),Char($3.text)); + LParse_typedef_resolve($$,0); + } +/* This declaration causes a shift-reduce conflict. Unresolved for now */ + | DCOLON TYPE_TYPEDEF { + $$ = NewLParseType(LPARSE_T_USER); + sprintf($$->name,"%s", Char($2.text)); + LParse_typedef_resolve($$,1); + } + | ENUM idtype { + $$ = NewLParseType(LPARSE_T_ENUM); + sprintf($$->name,"enum %s", Char($2.text)); + /* LParse_typedef_resolve($$,1);*/ + /* $$->typedef_resolve(1); */ + } + ; + +/* Optional signed types */ +opt_signed : empty { $$ = 0; } + | TYPE_INT { + $$ = NewLParseType(LPARSE_T_INT); + strcpy($$->name,"signed int"); + } + | TYPE_SHORT opt_int { + $$ = NewLParseType(LPARSE_T_SHORT); + strcpy($$->name,"signed short"); + } + | TYPE_LONG opt_int { + $$ = NewLParseType(LPARSE_T_LONG); + strcpy($$->name,"signed long"); + } + | TYPE_CHAR { + $$ = NewLParseType(LPARSE_T_SCHAR); + } + ; + +/* Optional unsigned types */ + +opt_unsigned : empty { $$ = 0;} + | TYPE_INT { + $$ = NewLParseType(LPARSE_T_UINT); + strcpy($$->name,"unsigned int"); + } + | TYPE_SHORT opt_int { + $$ = NewLParseType(LPARSE_T_USHORT); + strcpy($$->name,"unsigned short"); + } + | TYPE_LONG opt_int { + $$ = NewLParseType(LPARSE_T_ULONG); + strcpy($$->name, "unsigned long"); + } + | TYPE_CHAR { + $$ = NewLParseType(LPARSE_T_UCHAR); + } + ; + +opt_int : TYPE_INT { } + | empty { } + ; + +cpptype : CLASS { $$ = $1; } + | STRUCT { $$ = $1; } + | UNION { $$ = $1; } + ; + +template_decl : LESSTHAN { + $$ = $1; + $$.text = LParse_skip_balanced('<','>'); + } + ; + +/* ----------------------------------------------------------------------------- + * -- 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(); + } + ; + +idtype : ID { $$ = $1; } + | TYPE_TYPEDEF { $$ = $1; } + ; + +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) { + if (Intype == 0) { + LParse_error(0,0,"Syntax error. Perhaps you need to specify a typename.\n"); + } else { + LParse_error(0,0,"Syntax error.\n", e); + } +} + + + + + + + + + + + diff --git a/Source/LParse/type.c b/Source/LParse/type.c new file mode 100644 index 000000000..25319f39d --- /dev/null +++ b/Source/LParse/type.c @@ -0,0 +1,407 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#include "lparse.h" + +/* ----------------------------------------------------------------------------- + * $Header$ + * + * type.c + * + * Lame type structure for old SWIG parser + * ----------------------------------------------------------------------------- */ + +extern DOH *LParseTypeStr(DOH *to); + +static DohObjInfo LParseTypeType = { + "LParseType", /* objname */ + sizeof(LParseType), /* objsize */ + DelLParseType, /* doh_del */ + CopyLParseType, /* doh_copy */ + 0, /* doh_clear */ + 0, /* doh_scope */ + LParseTypeStr, /* doh_str */ + 0, /* doh_data */ + 0, /* doh_dump */ + 0, /* doh_load */ + 0, /* doh_len */ + 0, /* doh_hash */ + 0, /* doh_cmp */ + 0, /* doh_mapping */ + 0, /* doh_sequence */ + 0, /* doh_file */ + 0, /* doh_string */ + 0, /* doh_callable */ + 0, /* doh_position */ +}; + +/* ----------------------------------------------------------------------------- + * NewLParseType() - Create a new datatype + * ----------------------------------------------------------------------------- */ +LParseType * +NewLParseType(int ty) { + LParseType *t = (LParseType *) DohObjMalloc(sizeof(LParseType)); + t->objinfo = &LParseTypeType; + t->type = ty; + t->name = (char *) malloc(LPARSE_MAX_NAME); + t->name[0] = 0; + t->is_pointer = 0; + t->implicit_ptr = 0; + t->is_reference = 0; + t->status = 0; + t->qualifier = 0; + t->arraystr = 0; + switch(ty) { + case LPARSE_T_INT: + strcpy(t->name,"int"); + break; + case LPARSE_T_UINT: + strcpy(t->name,"unsigned"); + break; + case LPARSE_T_SHORT: + strcpy(t->name,"short"); + break; + case LPARSE_T_USHORT: + strcpy(t->name,"unsigned short"); + break; + case LPARSE_T_LONG: + strcpy(t->name,"long"); + break; + case LPARSE_T_ULONG: + strcpy(t->name,"unsigned long"); + break; + case LPARSE_T_FLOAT: + strcpy(t->name,"float"); + break; + case LPARSE_T_DOUBLE: + strcpy(t->name,"double"); + break; + case LPARSE_T_CHAR: + strcpy(t->name,"char"); + break; + case LPARSE_T_SCHAR: + strcpy(t->name,"signed char"); + break; + case LPARSE_T_UCHAR: + strcpy(t->name,"unsigned char"); + break; + case LPARSE_T_VOID: + strcpy(t->name,"void"); + break; + case LPARSE_T_BOOL: + strcpy(t->name,"bool"); + break; + default: + break; + } + return t; +} + +/* ----------------------------------------------------------------------------- + * DelLParseType() - Destroy a datatype + * ----------------------------------------------------------------------------- */ +void DelLParseType(DOH *t) { + LParseType *ty = (LParseType *) t; + assert(ty->refcount <= 0); + free(ty->name); + if (ty->qualifier) free(ty->qualifier); + if (ty->arraystr) free(ty->arraystr); +} + +/* ----------------------------------------------------------------------------- + * CopyLParseType() - Copy a type + * ----------------------------------------------------------------------------- */ +DOH * +CopyLParseType(DOH *co) { + LParseType *c; + LParseType *t = (LParseType *) DohObjMalloc(sizeof(LParseType)); + c = (LParseType *) co; + t->objinfo = &LParseTypeType; + t->type = c->type; + t->name = (char *) malloc(LPARSE_MAX_NAME); + strcpy(t->name,c->name); + t->is_pointer = c->is_pointer; + t->implicit_ptr = c->implicit_ptr; + t->is_reference = c->is_reference; + t->status = c->status; + t->qualifier = copy_string(c->qualifier); + t->arraystr = copy_string(c->arraystr); + return t; +} + +/* ----------------------------------------------------------------------------- + * LParseTypeStr() - Make a string of a datatype. + * ----------------------------------------------------------------------------- */ +DOH * +LParseTypeStr(DOH *to) { + DOH *s; + int i; + LParseType *t = (LParseType *) to; + s = NewString(""); + Printf(s,"(%d) - ", t->type); + if (t->qualifier) + Printf(s,"%s ",t->qualifier); + Printf(s,"%s ",t->name); + if (t->is_reference || t->arraystr) t->is_pointer--; + for (i = 0; i < t->is_pointer; i++) + Putc('*',s); + if (t->is_reference || t->arraystr) t->is_pointer++; + if (t->is_reference) + Putc('&',s); + if (t->arraystr) + Printf(s,"%s", t->arraystr); + return s; +} + +/* ----------------------------------------------------------------------------- + * --- typedef support --- + * ----------------------------------------------------------------------------- */ + +#define MAXSCOPE 256 +static DOH *typedef_hash[MAXSCOPE]; +static int scope = 0; +static int typedef_init = 0; + +static void init_typedef() { + int i; + for (i = 0; i < MAXSCOPE; i++) + typedef_hash[i] = 0; + scope = 0; + typedef_hash[scope] = NewHash(); + typedef_init = 1; +} + +/* ----------------------------------------------------------------------------- + * void LParse_typedef_add(LParseType *t, DOH *tname) + * + * Create a new typedef. + * ----------------------------------------------------------------------------- */ + +void LParse_typedef_add(LParseType *t, DOH *tname) { + LParseType *nt; + + if (!typedef_init) init_typedef(); + /* Check to see if the type already exists */ + if ((nt = (LParseType *) Getattr(typedef_hash[scope],tname))) { + Printf(stderr,"Warning. Datatype %s already defined (2nd definition ignored).\n", tname); + return; + } + + nt = (LParseType *) CopyLParseType(t); + nt->implicit_ptr = (t->is_pointer-t->implicit_ptr); /* Record if mapped type is a pointer */ + nt->is_pointer = (t->is_pointer-t->implicit_ptr); /* Adjust pointer value to be correct */ + LParse_typedef_resolve(nt,0); /* Resolve any other mappings of this type */ + + /* Add this type to our hash table */ + Setattr(typedef_hash[scope],tname, nt); +} + +/* ----------------------------------------------------------------------------- + * void LParse_typedef_resolve(LParseType *t, int level = 0) + * + * Checks to see if this datatype is in the typedef hash and + * resolves it if necessary. This will check all of the typedef + * hash tables we know about. + * + * level is an optional parameter that determines which scope to use. + * Usually this is only used with a bare :: operator in a datatype. + * + * The const headache : + * + * Normally SWIG will fail if a const variable is used in a typedef + * like this : + * + * typedef const char *String; + * + * This is because future occurrences of "String" will be treated like + * a char *, but without regard to the "constness". To work around + * this problem. The resolve() method checks to see if these original + * data type is const. If so, we'll substitute the name of the original + * datatype instead. Got it? + * ----------------------------------------------------------------------------- */ + +void LParse_typedef_resolve(LParseType *t, int level) { + LParseType *td; + int s = scope - level; + + if (!typedef_init) init_typedef(); + while (s >= 0) { + if ((td = (LParseType *) Getattr(typedef_hash[s],t->name))) { + t->type = td->type; + t->is_pointer += td->is_pointer; + t->implicit_ptr += td->implicit_ptr; + t->status = t->status | td->status; + + /* Check for constness, and replace type name if necessary */ + + if (td->qualifier) { + if (strcmp(td->qualifier,"const") == 0) { + strcpy(t->name,td->name); + t->qualifier = copy_string(td->qualifier); + t->implicit_ptr -= td->implicit_ptr; + } + } + return; + } + s--; + } + /* Not found, do nothing */ + return; +} + +/* ----------------------------------------------------------------------------- + * void LParse_typedef_replace() + * + * Checks to see if this datatype is in the typedef hash and + * replaces it with the hash entry. Only applies to current scope. + * ----------------------------------------------------------------------------- */ + +void LParse_typedef_replace(LParseType *t) { + LParseType *td; + DOH *temp; + + if (!typedef_init) init_typedef(); + temp = NewString(""); + if ((td = (LParseType *) Getattr(typedef_hash[scope],t->name))) { + t->type = td->type; + t->is_pointer = td->is_pointer; + t->implicit_ptr -= td->implicit_ptr; + strcpy(t->name, td->name); + if (td->arraystr) { + if (t->arraystr) { + Printf(temp,"%s", t->arraystr); + free(t->arraystr); + } + Printf(temp,"%s", td->arraystr); + t->arraystr = copy_string(Char(temp)); + } + } + Delete(temp); + /* Not found, do nothing */ + return; +} + +/* ----------------------------------------------------------------------------- + * int LParse_typedef_check(DOH *tname) + * + * Checks to see whether tname is the name of a datatype we know + * about. Returns 1 if there's a match, 0 otherwise + * ----------------------------------------------------------------------------- */ + +int LParse_typedef_check(DOH *tname) { + int s = scope; + if (!typedef_init) init_typedef(); + while (s >= 0) { + if (Getattr(typedef_hash[s],tname)) return 1; + s--; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * void LParse_typedef_updatestatus(LParseType *t, int newstatus) + * + * Checks to see if this datatype is in the hash table. If + * so, we'll update its status. This is sometimes used with + * typemap handling. Only applies to current scope. + * ----------------------------------------------------------------------------- */ +void LParse_typedef_updatestatus(LParseType *t, int newstatus) { + LParseType *td; + if (!typedef_init) init_typedef(); + if ((td = (LParseType *) Getattr(typedef_hash[scope], t->name))) { + td->status = newstatus; + } +} + +/* ----------------------------------------------------------------------------- + * void LParse_merge_scope(DOH *h) + * + * Copies all of the entries in scope h into the current scope. This is + * primarily done with C++ inheritance. + * ----------------------------------------------------------------------------- */ + +void LParse_merge_scope(DOH *h) { + DOH *key; + DOH *nt; + + if (!typedef_init) init_typedef(); + if (h) { + /* Copy all of the entries in the given hash table to this new one */ + key = Firstkey(h); + while (key) { + nt = Copy(Getattr(h,key)); + Setattr(typedef_hash[scope],key,nt); + key = Nextkey(h); + } + } +} + +/* ----------------------------------------------------------------------------- + * void LParse_new_scope(DOH *h) + * + * Creates a new scope for handling typedefs. This is used in C++ handling + * to create typedef local to a class definition. + * ----------------------------------------------------------------------------- */ + +void LParse_new_scope(DOH *h) { + if (!typedef_init) init_typedef(); + scope++; + typedef_hash[scope] = NewHash(); + if (h) { + LParse_merge_scope(h); + } +} + +/* ----------------------------------------------------------------------------- + * DOH *LParse_collapse_scope(DOH *prefix) + * + * Collapses the current scope into the previous one, but applies a prefix to + * all of the datatypes. This is done in order to properly handle C++ stuff. + * For example : + * + * class Foo { + * ... + * typedef double Real; + * } + * + * will have a type mapping of "double --> Real" within the class itself. + * When we collapse the scope, this mapping will become "double --> Foo::Real" + * ----------------------------------------------------------------------------- */ + +DOH *LParse_collapse_scope(DOH *prefix) { + LParseType *nt; + DOH *key; + DOH *temp; + DOH *h; + + if (!typedef_init) init_typedef(); + if (scope > 0) { + if (prefix) { + key = Firstkey(typedef_hash[scope]); + while (key) { + nt = (LParseType *) Copy(Getattr(typedef_hash[scope],key)); + temp = NewString(""); + Printf(temp,"%s::%s", prefix,key); + Setattr(typedef_hash[scope-1],temp,nt); + key = Nextkey(typedef_hash[scope]); + } + } + h = typedef_hash[scope]; + typedef_hash[scope] = 0; + scope--; + return h; + } + return 0; +}