| /* |
| |
| soapcpp2_yacc.y |
| |
| Yacc/Bison grammar. |
| |
| Notes: |
| |
| Bison 1.6 can crash on Win32 systems if YYINITDEPTH is too small Compile with |
| -DYYINITDEPTH=5000 |
| |
| This grammar has one shift/reduce conflict related to the use of a class |
| declaration with a base class (e.g. class Y : public X) and the use of a |
| maxOccurs (class Y :10). Internally the conflict is resolved in favor of a |
| shift by Bison/Yacc, which leads to the correct parsing behavior. Therefore, |
| the warning can be ignored. |
| |
| gSOAP XML Web services tools |
| Copyright (C) 2000-2005, Robert van Engelen, Genivia Inc. All Rights Reserved. |
| This part of the software is released under one of the following licenses: |
| GPL, the gSOAP public license, or Genivia's license for commercial use. |
| -------------------------------------------------------------------------------- |
| gSOAP public license. |
| |
| The contents of this file are subject to the gSOAP Public License Version 1.3 |
| (the "License"); you may not use this file except in compliance with the |
| License. You may obtain a copy of the License at |
| http://www.cs.fsu.edu/~engelen/soaplicense.html |
| Software distributed under the License is distributed on an "AS IS" basis, |
| WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
| for the specific language governing rights and limitations under the License. |
| |
| The Initial Developer of the Original Code is Robert A. van Engelen. |
| Copyright (C) 2000-2004 Robert A. van Engelen, Genivia inc. All Rights Reserved. |
| -------------------------------------------------------------------------------- |
| GPL license. |
| |
| This program is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free Software |
| Foundation; either version 2 of the License, or (at your option) any later |
| version. |
| |
| This program is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
| PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License along with |
| this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
| Place, Suite 330, Boston, MA 02111-1307 USA |
| |
| Author contact information: |
| engelen@genivia.com / engelen@acm.org |
| -------------------------------------------------------------------------------- |
| A commercial use license is available from Genivia, Inc., contact@genivia.com |
| -------------------------------------------------------------------------------- |
| */ |
| |
| %{ |
| |
| #include "soapcpp2.h" |
| #ifdef WIN32 |
| extern int soapcpp2lex(); |
| #endif |
| |
| #define MAXNEST 16 /* max. nesting depth of scopes */ |
| |
| struct Scope |
| { Table *table; |
| Entry *entry; |
| Node node; |
| LONG64 val; |
| int offset; |
| Bool grow; /* true if offset grows with declarations */ |
| Bool mask; /* true if enum is mask */ |
| } stack[MAXNEST], /* stack of tables and offsets */ |
| *sp; /* current scope stack pointer */ |
| |
| Table *classtable = (Table*)0, |
| *enumtable = (Table*)0, |
| *typetable = (Table*)0, |
| *booltable = (Table*)0, |
| *templatetable = (Table*)0; |
| |
| char *namespaceid = NULL; |
| int transient = 0; |
| int permission = 0; |
| int custom_header = 1; |
| int custom_fault = 1; |
| Pragma *pragmas = NULL; |
| Tnode *qname = NULL; |
| Tnode *xml = NULL; |
| |
| /* function prototypes for support routine section */ |
| static Entry *undefined(Symbol*); |
| static Tnode *mgtype(Tnode*, Tnode*); |
| static Node op(const char*, Node, Node), iop(const char*, Node, Node), relop(const char*, Node, Node); |
| static void mkscope(Table*, int), enterscope(Table*, int), exitscope(); |
| static int integer(Tnode*), real(Tnode*), numeric(Tnode*), pointer(Tnode*); |
| static void add_XML(), add_qname(), add_header(Table*), add_fault(Table*), add_response(Entry*, Entry*), add_result(Tnode*); |
| extern char *c_storage(Storage), *c_type(Tnode*), *c_ident(Tnode*); |
| extern int is_primitive_or_string(Tnode*), is_stdstr(Tnode*), is_binary(Tnode*); |
| |
| /* temporaries used in semantic rules */ |
| int i; |
| char *s, *s1, *s2; |
| Symbol *sym; |
| Entry *p, *q; |
| Tnode *t; |
| Node tmp, c; |
| Pragma **pp; |
| |
| %} |
| |
| /* we expect one shift-reduce conflict */ |
| %expect 1 |
| /* remove this line if necessary to allow Yacc to proceed */ |
| |
| %union |
| { Symbol *sym; |
| LONG64 i; |
| double r; |
| char c; |
| char *s; |
| Tnode *typ; |
| Storage sto; |
| Node rec; |
| Entry *e; |
| } |
| |
| /* pragmas */ |
| %token <s> PRAGMA |
| /* keywords */ |
| %token <sym> AUTO DOUBLE INT STRUCT |
| %token <sym> BREAK ELSE LONG SWITCH |
| %token <sym> CASE ENUM REGISTER TYPEDEF |
| %token <sym> CHAR EXTERN RETURN UNION |
| %token <sym> CONST FLOAT SHORT UNSIGNED |
| %token <sym> CONTINUE FOR SIGNED VOID |
| %token <sym> DEFAULT GOTO SIZEOF VOLATILE |
| %token <sym> DO IF STATIC WHILE |
| %token <sym> CLASS PRIVATE PROTECTED PUBLIC |
| %token <sym> VIRTUAL INLINE OPERATOR LLONG |
| %token <sym> BOOL CFALSE CTRUE WCHAR |
| %token <sym> TIME USING NAMESPACE ULLONG |
| %token <sym> MUSTUNDERSTAND SIZE FRIEND |
| %token <sym> TEMPLATE EXPLICIT TYPENAME |
| %token <sym> RESTRICT null |
| /* */ |
| %token NONE |
| /* identifiers (TYPE = typedef identifier) */ |
| %token <sym> ID TYPE |
| /* constants */ |
| %token <i> LNG |
| %token <r> DBL |
| %token <c> CHR |
| %token <s> STR |
| /* types and related */ |
| %type <typ> type |
| %type <sto> store virtual constobj abstract |
| %type <e> fname struct class super |
| %type <sym> id arg name |
| %type <s> patt |
| %type <i> cint |
| /* expressions and statements */ |
| %type <rec> expr cexp oexp obex aexp abex rexp lexp pexp init spec tspec ptrs array arrayck texp qexp occurs |
| /* terminals */ |
| %left ',' |
| %right '=' PA NA TA DA MA AA XA OA LA RA /* += -= *= /= %= &= ^= |= <<= >>= */ |
| %right '?' |
| %right ':' |
| %left OR /* || */ |
| %left AN /* && */ |
| %left '|' |
| %left '^' |
| %left '&' |
| %left EQ NE /* == != */ |
| %left '<' LE '>' GE /* <= >= */ |
| %left LS RS /* << >> */ |
| %left '+' '-' |
| %left '*' '/' '%' |
| %left AR /* -> */ |
| %token PP NN /* ++ -- */ |
| |
| %% |
| |
| /******************************************************************************\ |
| |
| Program syntax |
| |
| \******************************************************************************/ |
| |
| prog : s1 exts { if (lflag) |
| { custom_header = 0; |
| custom_fault = 0; |
| } |
| else |
| { add_header(sp->table); |
| add_fault(sp->table); |
| } |
| compile(sp->table); |
| freetable(classtable); |
| freetable(enumtable); |
| freetable(typetable); |
| freetable(booltable); |
| freetable(templatetable); |
| } |
| ; |
| s1 : /* empty */ { classtable = mktable((Table*)0); |
| enumtable = mktable((Table*)0); |
| typetable = mktable((Table*)0); |
| booltable = mktable((Table*)0); |
| templatetable = mktable((Table*)0); |
| p = enter(booltable, lookup("false")); |
| p->info.typ = mkint(); |
| p->info.val.i = 0; |
| p = enter(booltable, lookup("true")); |
| p->info.typ = mkint(); |
| p->info.val.i = 1; |
| mkscope(mktable(mktable((Table*)0)), 0); |
| } |
| ; |
| exts : NAMESPACE ID '{' exts1 '}' |
| { namespaceid = $2->name; } |
| | exts1 { namespaceid = NULL; } |
| ; |
| exts1 : /* empty */ { if (!lflag) |
| { add_XML(); |
| add_qname(); |
| } |
| } |
| | exts1 ext { } |
| ; |
| ext : dclrs ';' { } |
| | pragma { } |
| | error ';' { synerror("input before ; skipped"); |
| while (sp > stack) |
| { freetable(sp->table); |
| exitscope(); |
| } |
| yyerrok; |
| } |
| | t1 { } |
| | t2 { } |
| ; |
| pragma : PRAGMA { if ($1[1] >= 'a' && $1[1] <= 'z') |
| { for (pp = &pragmas; *pp; pp = &(*pp)->next) |
| ; |
| *pp = (Pragma*)emalloc(sizeof(Pragma)); |
| (*pp)->pragma = (char*)emalloc(strlen($1)+1); |
| strcpy((*pp)->pragma, $1); |
| (*pp)->next = NULL; |
| } |
| else if ((i = atoi($1+2)) > 0) |
| yylineno = i; |
| else |
| { sprintf(errbuf, "directive '%s' ignored (use #import to import files and/or use option -i)", $1); |
| semwarn(errbuf); |
| } |
| } |
| ; |
| |
| /******************************************************************************\ |
| |
| Declarations |
| |
| \******************************************************************************/ |
| |
| decls : /* empty */ { transient &= ~6; |
| permission = 0; |
| } |
| | dclrs ';' decls |
| { } |
| | PRIVATE ':' t3 decls |
| { } |
| | PROTECTED ':' t4 decls |
| { } |
| | PUBLIC ':' t5 decls |
| { } |
| | t1 decls t2 decls |
| { } |
| ; |
| t1 : '[' { transient |= 1; |
| } |
| ; |
| t2 : ']' { transient &= ~1; |
| } |
| ; |
| t3 : { permission = Sprivate; |
| } |
| ; |
| t4 : { permission = Sprotected; |
| } |
| ; |
| t5 : { permission = 0; |
| } |
| ; |
| dclrs : spec { } |
| | spec dclr { } |
| | spec fdclr func |
| { } |
| | constr func { } |
| | destr func { } |
| | dclrs ',' dclr{ } |
| | dclrs ',' fdclr func |
| { } |
| ; |
| dclr : ptrs ID arrayck occurs init |
| { if (($3.sto & Stypedef) && sp->table->level == GLOBAL) |
| { if (($3.typ->type != Tstruct && $3.typ->type != Tunion && $3.typ->type != Tenum) || strcmp($2->name, $3.typ->id->name)) |
| |
| { p = enter(typetable, $2); |
| p->info.typ = mksymtype($3.typ, $2); |
| if ($3.sto & Sextern) |
| p->info.typ->transient = -1; |
| else |
| p->info.typ->transient = $3.typ->transient; |
| p->info.sto = $3.sto; |
| p->info.typ->pattern = $4.pattern; |
| if ($4.minOccurs != -1) |
| { p->info.typ->minLength = $4.minOccurs; |
| } |
| if ($4.maxOccurs > 1) |
| p->info.typ->maxLength = $4.maxOccurs; |
| } |
| $2->token = TYPE; |
| } |
| else |
| { p = enter(sp->table, $2); |
| p->info.typ = $3.typ; |
| p->info.sto = ($3.sto | permission); |
| if ($5.hasval) |
| { p->info.hasval = True; |
| switch ($3.typ->type) |
| { case Tchar: |
| case Tuchar: |
| case Tshort: |
| case Tushort: |
| case Tint: |
| case Tuint: |
| case Tlong: |
| case Tulong: |
| case Tllong: |
| case Tullong: |
| case Tenum: |
| case Ttime: |
| if ($5.typ->type == Tint || $5.typ->type == Tchar || $5.typ->type == Tenum) |
| sp->val = p->info.val.i = $5.val.i; |
| else |
| { semerror("type error in initialization constant"); |
| p->info.hasval = False; |
| } |
| break; |
| case Tfloat: |
| case Tdouble: |
| if ($5.typ->type == Tfloat || $5.typ->type == Tdouble) |
| p->info.val.r = $5.val.r; |
| else if ($5.typ->type == Tint) |
| p->info.val.r = (double)$5.val.i; |
| else |
| { semerror("type error in initialization constant"); |
| p->info.hasval = False; |
| } |
| break; |
| default: |
| if ($3.typ->type == Tpointer |
| && ((Tnode*)$3.typ->ref)->type == Tchar |
| && $5.typ->type == Tpointer |
| && ((Tnode*)$5.typ->ref)->type == Tchar) |
| p->info.val.s = $5.val.s; |
| else if ($3.typ->type == Tpointer |
| && ((Tnode*)$3.typ->ref)->id == lookup("std::string")) |
| p->info.val.s = $5.val.s; |
| else if ($3.typ->id == lookup("std::string")) |
| p->info.val.s = $5.val.s; |
| else if ($3.typ->type == Tpointer |
| && $5.typ->type == Tint |
| && $5.val.i == 0) |
| p->info.val.i = 0; |
| else |
| { semerror("type error in initialization constant"); |
| p->info.hasval = False; |
| } |
| break; |
| } |
| } |
| else |
| p->info.val.i = sp->val; |
| if ($4.minOccurs < 0) |
| { if (($3.sto & Sattribute) || $3.typ->type == Tpointer || $3.typ->type == Ttemplate || !strncmp($2->name, "__size", 6)) |
| p->info.minOccurs = 0; |
| else |
| p->info.minOccurs = 1; |
| } |
| else |
| p->info.minOccurs = $4.minOccurs; |
| p->info.maxOccurs = $4.maxOccurs; |
| if (sp->mask) |
| sp->val <<= 1; |
| else |
| sp->val++; |
| p->info.offset = sp->offset; |
| if ($3.sto & Sextern) |
| p->level = GLOBAL; |
| else if ($3.sto & Stypedef) |
| ; |
| else if (sp->grow) |
| sp->offset += p->info.typ->width; |
| else if (p->info.typ->width > sp->offset) |
| sp->offset = p->info.typ->width; |
| } |
| sp->entry = p; |
| } |
| ; |
| fdclr : ptrs name { if ($1.sto & Stypedef) |
| { sprintf(errbuf, "invalid typedef qualifier for '%s'", $2->name); |
| semwarn(errbuf); |
| } |
| p = enter(sp->table, $2); |
| p->info.typ = $1.typ; |
| p->info.sto = $1.sto; |
| p->info.hasval = False; |
| p->info.offset = sp->offset; |
| if (sp->grow) |
| sp->offset += p->info.typ->width; |
| else if (p->info.typ->width > sp->offset) |
| sp->offset = p->info.typ->width; |
| sp->entry = p; |
| } |
| ; |
| id : ID { $$ = $1; } |
| | TYPE { $$ = $1; } |
| ; |
| name : ID { $$ = $1; } |
| | OPERATOR '!' { $$ = lookup("operator!"); } |
| | OPERATOR '~' { $$ = lookup("operator~"); } |
| | OPERATOR '=' { $$ = lookup("operator="); } |
| | OPERATOR PA { $$ = lookup("operator+="); } |
| | OPERATOR NA { $$ = lookup("operator-="); } |
| | OPERATOR TA { $$ = lookup("operator*="); } |
| | OPERATOR DA { $$ = lookup("operator/="); } |
| | OPERATOR MA { $$ = lookup("operator%="); } |
| | OPERATOR AA { $$ = lookup("operator&="); } |
| | OPERATOR XA { $$ = lookup("operator^="); } |
| | OPERATOR OA { $$ = lookup("operator|="); } |
| | OPERATOR LA { $$ = lookup("operator<<="); } |
| | OPERATOR RA { $$ = lookup("operator>>="); } |
| | OPERATOR OR { $$ = lookup("operator||"); } |
| | OPERATOR AN { $$ = lookup("operator&&"); } |
| | OPERATOR '|' { $$ = lookup("operator|"); } |
| | OPERATOR '^' { $$ = lookup("operator^"); } |
| | OPERATOR '&' { $$ = lookup("operator&"); } |
| | OPERATOR EQ { $$ = lookup("operator=="); } |
| | OPERATOR NE { $$ = lookup("operator!="); } |
| | OPERATOR '<' { $$ = lookup("operator<"); } |
| | OPERATOR LE { $$ = lookup("operator<="); } |
| | OPERATOR '>' { $$ = lookup("operator>"); } |
| | OPERATOR GE { $$ = lookup("operator>="); } |
| | OPERATOR LS { $$ = lookup("operator<<"); } |
| | OPERATOR RS { $$ = lookup("operator>>"); } |
| | OPERATOR '+' { $$ = lookup("operator+"); } |
| | OPERATOR '-' { $$ = lookup("operator-"); } |
| | OPERATOR '*' { $$ = lookup("operator*"); } |
| | OPERATOR '/' { $$ = lookup("operator/"); } |
| | OPERATOR '%' { $$ = lookup("operator%"); } |
| | OPERATOR PP { $$ = lookup("operator++"); } |
| | OPERATOR NN { $$ = lookup("operator--"); } |
| | OPERATOR AR { $$ = lookup("operator->"); } |
| | OPERATOR'['']'{ $$ = lookup("operator[]"); } |
| | OPERATOR'('')'{ $$ = lookup("operator()"); } |
| | OPERATOR texp { s1 = c_storage($2.sto); |
| s2 = c_type($2.typ); |
| s = (char*)emalloc(strlen(s1) + strlen(s2) + 10); |
| strcpy(s, "operator "); |
| strcat(s, s1); |
| strcat(s, s2); |
| $$ = lookup(s); |
| if (!$$) |
| $$ = install(s, ID); |
| } |
| ; |
| constr : TYPE { if (!(p = entry(classtable, $1))) |
| semerror("invalid constructor"); |
| sp->entry = enter(sp->table, $1); |
| sp->entry->info.typ = mknone(); |
| sp->entry->info.sto = Snone; |
| sp->entry->info.offset = sp->offset; |
| sp->node.typ = mkvoid(); |
| sp->node.sto = Snone; |
| } |
| ; |
| destr : virtual '~' TYPE |
| { if (!(p = entry(classtable, $3))) |
| semerror("invalid destructor"); |
| s = (char*)emalloc(strlen($3->name) + 2); |
| strcpy(s, "~"); |
| strcat(s, $3->name); |
| sym = lookup(s); |
| if (!sym) |
| sym = install(s, ID); |
| sp->entry = enter(sp->table, sym); |
| sp->entry->info.typ = mknone(); |
| sp->entry->info.sto = $1; |
| sp->entry->info.offset = sp->offset; |
| sp->node.typ = mkvoid(); |
| sp->node.sto = Snone; |
| } |
| ; |
| func : fname '(' s6 fargso ')' constobj abstract |
| { if ($1->level == GLOBAL) |
| { if (!($1->info.sto & Sextern) && sp->entry && sp->entry->info.typ->type == Tpointer && ((Tnode*)sp->entry->info.typ->ref)->type == Tchar) |
| { sprintf(errbuf, "last output parameter of remote method function prototype '%s' is a pointer to a char which will only return one byte: use char** instead to return a string", $1->sym->name); |
| semwarn(errbuf); |
| } |
| if ($1->info.sto & Sextern) |
| $1->info.typ = mkmethod($1->info.typ, sp->table); |
| else if (sp->entry && (sp->entry->info.typ->type == Tpointer || sp->entry->info.typ->type == Treference || sp->entry->info.typ->type == Tarray || is_transient(sp->entry->info.typ))) |
| { if ($1->info.typ->type == Tint) |
| { sp->entry->info.sto = (Storage)((int)sp->entry->info.sto | (int)Sreturn); |
| $1->info.typ = mkfun(sp->entry); |
| $1->info.typ->id = $1->sym; |
| if (!is_transient(sp->entry->info.typ)) |
| if (!is_response(sp->entry->info.typ)) |
| { if (!is_XML(sp->entry->info.typ)) |
| add_response($1, sp->entry); |
| } |
| else |
| add_result(sp->entry->info.typ); |
| } |
| else |
| { sprintf(errbuf, "return type of remote method function prototype '%s' must be integer", $1->sym->name); |
| semerror(errbuf); |
| } |
| } |
| else |
| { sprintf(errbuf, "last output parameter of remote method function prototype '%s' is a return parameter and must be a pointer or reference", $1->sym->name); |
| semerror(errbuf); |
| } |
| if (!($1->info.sto & Sextern)) |
| { unlinklast(sp->table); |
| if ((p = entry(classtable, $1->sym))) |
| { if ((Table*) p->info.typ->ref) |
| { sprintf(errbuf, "remote method name clash: struct/class '%s' already declared at line %d", $1->sym->name, p->lineno); |
| semerror(errbuf); |
| } |
| else |
| { p->info.typ->ref = sp->table; |
| p->info.typ->width = sp->offset; |
| } |
| } |
| else |
| { p = enter(classtable, $1->sym); |
| p->info.typ = mkstruct(sp->table, sp->offset); |
| p->info.typ->id = $1->sym; |
| } |
| } |
| } |
| else if ($1->level == INTERNAL) |
| { $1->info.typ = mkmethod($1->info.typ, sp->table); |
| $1->info.sto = (Storage)((int)$1->info.sto | (int)$6 | (int)$7); |
| transient &= ~1; |
| } |
| exitscope(); |
| } |
| ; |
| fname : { $$ = sp->entry; } |
| ; |
| fargso : /* empty */ { } |
| | fargs { } |
| ; |
| fargs : farg { } |
| | farg ',' fargs{ } |
| ; |
| farg : tspec ptrs arg arrayck occurs init |
| { if ($4.sto & Stypedef) |
| semwarn("typedef in function argument"); |
| p = enter(sp->table, $3); |
| p->info.typ = $4.typ; |
| p->info.sto = $4.sto; |
| if ($5.minOccurs < 0) |
| { if (($4.sto & Sattribute) || $4.typ->type == Tpointer) |
| p->info.minOccurs = 0; |
| else |
| p->info.minOccurs = 1; |
| } |
| else |
| p->info.minOccurs = $5.minOccurs; |
| p->info.maxOccurs = $5.maxOccurs; |
| if ($6.hasval) |
| { p->info.hasval = True; |
| switch ($4.typ->type) |
| { case Tchar: |
| case Tuchar: |
| case Tshort: |
| case Tushort: |
| case Tint: |
| case Tuint: |
| case Tlong: |
| case Tulong: |
| case Tenum: |
| case Ttime: |
| if ($6.typ->type == Tint || $6.typ->type == Tchar || $6.typ->type == Tenum) |
| sp->val = p->info.val.i = $6.val.i; |
| else |
| { semerror("type error in initialization constant"); |
| p->info.hasval = False; |
| } |
| break; |
| case Tfloat: |
| case Tdouble: |
| if ($6.typ->type == Tfloat || $6.typ->type == Tdouble) |
| p->info.val.r = $6.val.r; |
| else if ($6.typ->type == Tint) |
| p->info.val.r = (double)$6.val.i; |
| else |
| { semerror("type error in initialization constant"); |
| p->info.hasval = False; |
| } |
| break; |
| default: |
| if ($4.typ->type == Tpointer |
| && ((Tnode*)$4.typ->ref)->type == Tchar |
| && $6.typ->type == Tpointer |
| && ((Tnode*)$6.typ->ref)->type == Tchar) |
| p->info.val.s = $6.val.s; |
| else if ($4.typ->type == Tpointer |
| && ((Tnode*)$4.typ->ref)->id == lookup("std::string")) |
| p->info.val.s = $6.val.s; |
| else if ($4.typ->id == lookup("std::string")) |
| p->info.val.s = $6.val.s; |
| else if ($4.typ->type == Tpointer |
| && $6.typ->type == Tint |
| && $6.val.i == 0) |
| p->info.val.i = 0; |
| else |
| { semerror("type error in initialization constant"); |
| p->info.hasval = False; |
| } |
| break; |
| } |
| } |
| p->info.offset = sp->offset; |
| if ($4.sto & Sextern) |
| p->level = GLOBAL; |
| else if (sp->grow) |
| sp->offset += p->info.typ->width; |
| else if (p->info.typ->width > sp->offset) |
| sp->offset = p->info.typ->width; |
| sp->entry = p; |
| } |
| ; |
| arg : /* empty */ { if (sp->table->level != PARAM) |
| $$ = gensymidx("param", ++sp->val); |
| else if (eflag) |
| $$ = gensymidx("_param", ++sp->val); |
| else |
| $$ = gensym("_param"); |
| } |
| | ID { if (vflag != 1 && *$1->name == '_' && sp->table->level == GLOBAL) |
| { sprintf(errbuf, "SOAP 1.2 does not support anonymous parameters '%s'", $1->name); |
| semwarn(errbuf); |
| } |
| $$ = $1; |
| } |
| ; |
| |
| /******************************************************************************\ |
| |
| Type specification |
| |
| \******************************************************************************/ |
| |
| /* texp : type expression (subset of C) */ |
| texp : tspec ptrs array |
| { $$ = $3; } |
| | tspec ptrs ID array |
| { $$ = $4; } |
| ; |
| spec : /*empty */ { $$.typ = mkint(); |
| $$.sto = Snone; |
| sp->node = $$; |
| } |
| | store spec { $$.typ = $2.typ; |
| $$.sto = (Storage)((int)$1 | (int)$2.sto); |
| if (($$.sto & Sattribute) && !is_primitive_or_string($2.typ) && !is_stdstr($2.typ) && !is_binary($2.typ)) |
| { semwarn("invalid attribute type"); |
| $$.sto &= ~Sattribute; |
| } |
| sp->node = $$; |
| if ($1 & Sextern) |
| transient = 0; |
| } |
| | type spec { if ($1->type == Tint) |
| switch ($2.typ->type) |
| { case Tchar: $$.typ = $2.typ; break; |
| case Tshort: $$.typ = $2.typ; break; |
| case Tint: $$.typ = $1; break; |
| case Tlong: $$.typ = $2.typ; break; |
| case Tllong: $$.typ = $2.typ; break; |
| default: semwarn("illegal use of 'signed'"); |
| $$.typ = $2.typ; |
| } |
| else if ($1->type == Tuint) |
| switch ($2.typ->type) |
| { case Tchar: $$.typ = mkuchar(); break; |
| case Tshort: $$.typ = mkushort(); break; |
| case Tint: $$.typ = $1; break; |
| case Tlong: $$.typ = mkulong(); break; |
| case Tllong: $$.typ = mkullong(); break; |
| default: semwarn("illegal use of 'unsigned'"); |
| $$.typ = $2.typ; |
| } |
| else if ($1->type == Tlong) |
| switch ($2.typ->type) |
| { case Tint: $$.typ = $1; break; |
| case Tlong: $$.typ = mkllong(); break; |
| case Tuint: $$.typ = mkulong(); break; |
| case Tulong: $$.typ = mkullong(); break; |
| default: semwarn("illegal use of 'long'"); |
| $$.typ = $2.typ; |
| } |
| else if ($1->type == Tulong) |
| switch ($2.typ->type) |
| { case Tint: $$.typ = $1; break; |
| case Tlong: $$.typ = mkullong(); break; |
| case Tuint: $$.typ = $1; break; |
| case Tulong: $$.typ = mkullong(); break; |
| default: semwarn("illegal use of 'long'"); |
| $$.typ = $2.typ; |
| } |
| else if ($2.typ->type == Tint) |
| $$.typ = $1; |
| else |
| semwarn("invalid type (missing ';'?)"); |
| $$.sto = $2.sto; |
| sp->node = $$; |
| } |
| ; |
| tspec : store { $$.typ = mkint(); |
| $$.sto = $1; |
| sp->node = $$; |
| if ($1 & Sextern) |
| transient = 0; |
| } |
| | type { $$.typ = $1; |
| $$.sto = Snone; |
| sp->node = $$; |
| } |
| | store tspec { $$.typ = $2.typ; |
| $$.sto = (Storage)((int)$1 | (int)$2.sto); |
| if (($$.sto & Sattribute) && !is_primitive_or_string($2.typ) && !is_stdstr($2.typ) && !is_binary($2.typ)) |
| { semwarn("invalid attribute type"); |
| $$.sto &= ~Sattribute; |
| } |
| sp->node = $$; |
| if ($1 & Sextern) |
| transient = 0; |
| } |
| | type tspec { if ($1->type == Tint) |
| switch ($2.typ->type) |
| { case Tchar: $$.typ = $2.typ; break; |
| case Tshort: $$.typ = $2.typ; break; |
| case Tint: $$.typ = $1; break; |
| case Tlong: $$.typ = $2.typ; break; |
| case Tllong: $$.typ = $2.typ; break; |
| default: semwarn("illegal use of 'signed'"); |
| $$.typ = $2.typ; |
| } |
| else if ($1->type == Tuint) |
| switch ($2.typ->type) |
| { case Tchar: $$.typ = mkuchar(); break; |
| case Tshort: $$.typ = mkushort(); break; |
| case Tint: $$.typ = $1; break; |
| case Tlong: $$.typ = mkulong(); break; |
| case Tllong: $$.typ = mkullong(); break; |
| default: semwarn("illegal use of 'unsigned'"); |
| $$.typ = $2.typ; |
| } |
| else if ($1->type == Tlong) |
| switch ($2.typ->type) |
| { case Tint: $$.typ = $1; break; |
| case Tlong: $$.typ = mkllong(); break; |
| case Tuint: $$.typ = mkulong(); break; |
| case Tulong: $$.typ = mkullong(); break; |
| default: semwarn("illegal use of 'long'"); |
| $$.typ = $2.typ; |
| } |
| else if ($1->type == Tulong) |
| switch ($2.typ->type) |
| { case Tint: $$.typ = $1; break; |
| case Tlong: $$.typ = mkullong(); break; |
| case Tuint: $$.typ = $1; break; |
| case Tulong: $$.typ = mkullong(); break; |
| default: semwarn("illegal use of 'long'"); |
| $$.typ = $2.typ; |
| } |
| else if ($2.typ->type == Tint) |
| $$.typ = $1; |
| else |
| semwarn("invalid type"); |
| $$.sto = $2.sto; |
| sp->node = $$; |
| } |
| ; |
| type : VOID { $$ = mkvoid(); } |
| | BOOL { $$ = mkbool(); } |
| | CHAR { $$ = mkchar(); } |
| | WCHAR { $$ = mkwchart(); } |
| | SHORT { $$ = mkshort(); } |
| | INT { $$ = mkint(); } |
| | LONG { $$ = mklong(); } |
| | LLONG { $$ = mkllong(); } |
| | ULLONG { $$ = mkullong(); } |
| | SIZE { $$ = mkulong(); } |
| | FLOAT { $$ = mkfloat(); } |
| | DOUBLE { $$ = mkdouble(); } |
| | SIGNED { $$ = mkint(); } |
| | UNSIGNED { $$ = mkuint(); } |
| | TIME { $$ = mktimet(); } |
| | TEMPLATE '<' tname id '>' CLASS id |
| { if (!(p = entry(templatetable, $7))) |
| { p = enter(templatetable, $7); |
| p->info.typ = mktemplate(NULL, $7); |
| $7->token = TYPE; |
| } |
| $$ = p->info.typ; |
| } |
| | CLASS '{' s2 decls '}' |
| { sym = gensym("_Struct"); |
| sprintf(errbuf, "anonymous class will be named '%s'", sym->name); |
| semwarn(errbuf); |
| if ((p = entry(classtable, sym))) |
| { if (p->info.typ->ref || p->info.typ->type != Tclass) |
| { sprintf(errbuf, "class '%s' already declared at line %d", sym->name, p->lineno); |
| semerror(errbuf); |
| } |
| } |
| else |
| { p = enter(classtable, sym); |
| p->info.typ = mkclass((Table*)0, 0); |
| } |
| sym->token = TYPE; |
| sp->table->sym = sym; |
| p->info.typ->ref = sp->table; |
| p->info.typ->width = sp->offset; |
| p->info.typ->id = sym; |
| $$ = p->info.typ; |
| exitscope(); |
| } |
| | class '{' s2 decls '}' |
| { p = reenter(classtable, $1->sym); |
| sp->table->sym = p->sym; |
| p->info.typ->ref = sp->table; |
| p->info.typ->width = sp->offset; |
| p->info.typ->id = p->sym; |
| if (p->info.typ->base) |
| sp->table->prev = (Table*)entry(classtable, p->info.typ->base)->info.typ->ref; |
| $$ = p->info.typ; |
| exitscope(); |
| } |
| | class ':' super '{' s2 decls '}' |
| { p = reenter(classtable, $1->sym); |
| sp->table->sym = p->sym; |
| if (!$3) |
| semerror("invalid base class"); |
| else |
| { sp->table->prev = (Table*)$3->info.typ->ref; |
| if (!sp->table->prev && !$3->info.typ->transient) |
| { sprintf(errbuf, "class '%s' has incomplete type", $3->sym->name); |
| semerror(errbuf); |
| } |
| } |
| p->info.typ->ref = sp->table; |
| p->info.typ->width = sp->offset; |
| p->info.typ->id = p->sym; |
| p->info.typ->base = $3->info.typ->id; |
| $$ = p->info.typ; |
| exitscope(); |
| } |
| | class { $1->info.typ->id = $1->sym; |
| $$ = $1->info.typ; |
| } |
| | class ':' super |
| { if (!$3) |
| semerror("invalid base class"); |
| else |
| { if (!$3->info.typ->ref && !$3->info.typ->transient) |
| { sprintf(errbuf, "class '%s' has incomplete type", $3->sym->name); |
| semerror(errbuf); |
| } |
| } |
| $1->info.typ->id = $1->sym; |
| $1->info.typ->base = $3->info.typ->id; |
| $$ = $1->info.typ; |
| } |
| | STRUCT '{' s2 decls '}' |
| { sym = gensym("_Struct"); |
| sprintf(errbuf, "anonymous struct will be named '%s'", sym->name); |
| semwarn(errbuf); |
| if ((p = entry(classtable, sym))) |
| { if (p->info.typ->ref || p->info.typ->type != Tstruct) |
| { sprintf(errbuf, "struct '%s' already declared at line %d", sym->name, p->lineno); |
| semerror(errbuf); |
| } |
| else |
| { p->info.typ->ref = sp->table; |
| p->info.typ->width = sp->offset; |
| } |
| } |
| else |
| { p = enter(classtable, sym); |
| p->info.typ = mkstruct(sp->table, sp->offset); |
| } |
| p->info.typ->id = sym; |
| $$ = p->info.typ; |
| exitscope(); |
| } |
| | struct '{' s2 decls '}' |
| { if ((p = entry(classtable, $1->sym)) && p->info.typ->ref) |
| { sprintf(errbuf, "struct '%s' already declared at line %d", $1->sym->name, p->lineno); |
| semerror(errbuf); |
| } |
| else |
| { p = reenter(classtable, $1->sym); |
| p->info.typ->ref = sp->table; |
| p->info.typ->width = sp->offset; |
| p->info.typ->id = p->sym; |
| } |
| $$ = p->info.typ; |
| exitscope(); |
| } |
| | STRUCT ID { if ((p = entry(classtable, $2))) |
| { if (p->info.typ->type == Tstruct) |
| $$ = p->info.typ; |
| else |
| { sprintf(errbuf, "'struct %s' redeclaration %s", $2->name); |
| semerror(errbuf); |
| $$ = mkint(); |
| } |
| } |
| else |
| { p = enter(classtable, $2); |
| $$ = p->info.typ = mkstruct((Table*)0, 0); |
| p->info.typ->id = $2; |
| } |
| } |
| | STRUCT TYPE { if ((p = entry(classtable, $2))) |
| { if (p->info.typ->type == Tstruct) |
| $$ = p->info.typ; |
| else |
| { sprintf(errbuf, "'struct %s' redeclaration %s", $2->name); |
| semerror(errbuf); |
| $$ = mkint(); |
| } |
| } |
| else |
| { p = enter(classtable, $2); |
| $$ = p->info.typ = mkstruct((Table*)0, 0); |
| p->info.typ->id = $2; |
| } |
| } |
| | UNION '{' s3 decls '}' |
| { sym = gensym("_Union"); |
| sprintf(errbuf, "anonymous union will be named '%s'", sym->name); |
| semwarn(errbuf); |
| $$ = mkunion(sp->table, sp->offset); |
| if ((p = entry(classtable, sym))) |
| { if ((Table*) p->info.typ->ref) |
| { sprintf(errbuf, "union or struct '%s' already declared at line %d", sym->name, p->lineno); |
| semerror(errbuf); |
| } |
| else |
| { p->info.typ->ref = sp->table; |
| p->info.typ->width = sp->offset; |
| } |
| } |
| else |
| { p = enter(classtable, sym); |
| p->info.typ = mkunion(sp->table, sp->offset); |
| } |
| p->info.typ->id = sym; |
| $$ = p->info.typ; |
| exitscope(); |
| } |
| | UNION id '{' s3 decls '}' |
| { if ((p = entry(classtable, $2))) |
| { if (p->info.typ->ref || p->info.typ->type != Tunion) |
| { sprintf(errbuf, "union '%s' already declared at line %d", $2->name, p->lineno); |
| semerror(errbuf); |
| p->info.typ; |
| } |
| else |
| { p = reenter(classtable, $2); |
| p->info.typ->ref = sp->table; |
| p->info.typ->width = sp->offset; |
| } |
| } |
| else |
| { p = enter(classtable, $2); |
| p->info.typ = mkunion(sp->table, sp->offset); |
| } |
| p->info.typ->id = $2; |
| $$ = p->info.typ; |
| exitscope(); |
| } |
| | UNION ID { if ((p = entry(classtable, $2))) |
| { if (p->info.typ->type == Tunion) |
| $$ = p->info.typ; |
| else |
| { sprintf(errbuf, "'union %s' redeclaration %s", $2->name); |
| semerror(errbuf); |
| $$ = mkint(); |
| } |
| } |
| else |
| { p = enter(classtable, $2); |
| $$ = p->info.typ = mkunion((Table*) 0, 0); |
| p->info.typ->id = $2; |
| } |
| } |
| | UNION TYPE { if ((p = entry(classtable, $2))) |
| { if (p->info.typ->type == Tunion) |
| $$ = p->info.typ; |
| else |
| { sprintf(errbuf, "'union %s' redeclaration %s", $2->name); |
| semerror(errbuf); |
| $$ = mkint(); |
| } |
| } |
| else |
| { p = enter(classtable, $2); |
| $$ = p->info.typ = mkunion((Table*) 0, 0); |
| p->info.typ->id = $2; |
| } |
| } |
| | ENUM '{' s2 dclrs s5 '}' |
| { sym = gensym("_Enum"); |
| sprintf(errbuf, "anonymous enum will be named '%s'", sym->name); |
| semwarn(errbuf); |
| if ((p = entry(enumtable, sym))) |
| { if ((Table*) p->info.typ->ref) |
| { sprintf(errbuf, "enum '%s' already declared at line %d", sym->name, p->lineno); |
| semerror(errbuf); |
| } |
| else |
| { p->info.typ->ref = sp->table; |
| p->info.typ->width = 4; /* 4 = enum */ |
| } |
| } |
| else |
| { p = enter(enumtable, sym); |
| p->info.typ = mkenum(sp->table); |
| } |
| p->info.typ->id = sym; |
| $$ = p->info.typ; |
| exitscope(); |
| } |
| | ENUM id '{' s2 dclrs s5 '}' |
| { if ((p = entry(enumtable, $2))) |
| { if ((Table*) p->info.typ->ref) |
| { sprintf(errbuf, "enum '%s' already declared at line %d", $2->name, p->lineno); |
| semerror(errbuf); |
| } |
| else |
| { p->info.typ->ref = sp->table; |
| p->info.typ->width = 4; /* 4 = enum */ |
| } |
| } |
| else |
| { p = enter(enumtable, $2); |
| p->info.typ = mkenum(sp->table); |
| } |
| p->info.typ->id = $2; |
| $$ = p->info.typ; |
| exitscope(); |
| } |
| | ENUM '*' id '{' s4 dclrs s5 '}' |
| { if ((p = entry(enumtable, $3))) |
| { if (p->info.typ->ref) |
| { sprintf(errbuf, "enum '%s' already declared at line %d", $3->name, p->lineno); |
| semerror(errbuf); |
| } |
| else |
| { p->info.typ->ref = sp->table; |
| p->info.typ->width = 8; /* 8 = mask */ |
| } |
| } |
| else |
| { p = enter(enumtable, $3); |
| p->info.typ = mkmask(sp->table); |
| } |
| p->info.typ->id = $3; |
| $$ = p->info.typ; |
| exitscope(); |
| } |
| | ENUM ID { if ((p = entry(enumtable, $2))) |
| $$ = p->info.typ; |
| else |
| { p = enter(enumtable, $2); |
| $$ = p->info.typ = mkenum((Table*)0); |
| p->info.typ->id = $2; |
| } |
| } |
| | ENUM TYPE { if ((p = entry(enumtable, $2))) |
| $$ = p->info.typ; |
| else |
| { p = enter(enumtable, $2); |
| $$ = p->info.typ = mkenum((Table*)0); |
| p->info.typ->id = $2; |
| } |
| } |
| | TYPE { if ((p = entry(typetable, $1))) |
| $$ = p->info.typ; |
| else if ((p = entry(classtable, $1))) |
| $$ = p->info.typ; |
| else if ((p = entry(enumtable, $1))) |
| $$ = p->info.typ; |
| else if ($1 == lookup("std::string") || $1 == lookup("std::wstring")) |
| { p = enter(classtable, $1); |
| $$ = p->info.typ = mkclass((Table*)0, 0); |
| p->info.typ->id = $1; |
| p->info.typ->transient = -2; |
| } |
| else |
| { sprintf(errbuf, "unknown type '%s'", $1->name); |
| semerror(errbuf); |
| $$ = mkint(); |
| } |
| } |
| | TYPE '<' texp '>' |
| { if ((p = entry(templatetable, $1))) |
| $$ = mktemplate($3.typ, $1); |
| else |
| { sprintf(errbuf, "invalid template '%s'", $1->name); |
| semerror(errbuf); |
| $$ = mkint(); |
| } |
| } |
| ; |
| struct : STRUCT id { if ((p = entry(classtable, $2))) |
| { if (p->info.typ->ref) |
| { sprintf(errbuf, "struct '%s' already declared at line %d", $2->name, p->lineno); |
| semerror(errbuf); |
| } |
| else |
| p = reenter(classtable, $2); |
| } |
| else |
| { p = enter(classtable, $2); |
| p->info.typ = mkstruct((Table*)0, 0); |
| } |
| $$ = p; |
| } |
| ; |
| class : CLASS id { if ((p = entry(classtable, $2))) |
| { if (p->info.typ->ref) |
| { sprintf(errbuf, "class '%s' already declared at line %d", $2->name, p->lineno); |
| semerror(errbuf); |
| } |
| else |
| p = reenter(classtable, $2); |
| } |
| else |
| { p = enter(classtable, $2); |
| p->info.typ = mkclass((Table*)0, 0); |
| p->info.typ->id = p->sym; |
| } |
| $2->token = TYPE; |
| $$ = p; |
| } |
| ; |
| tname : CLASS { } |
| | TYPENAME { } |
| ; |
| super : PROTECTED TYPE{ $$ = entry(classtable, $2); } |
| | PRIVATE TYPE { $$ = entry(classtable, $2); } |
| | PUBLIC TYPE { $$ = entry(classtable, $2); } |
| | TYPE { $$ = entry(classtable, $1); } |
| ; |
| s2 : /* empty */ { if (transient == -2) |
| transient = 0; |
| permission = 0; |
| enterscope(mktable(NULL), 0); |
| sp->entry = NULL; |
| } |
| ; |
| s3 : /* empty */ { if (transient == -2) |
| transient = 0; |
| permission = 0; |
| enterscope(mktable(NULL), 0); |
| sp->entry = NULL; |
| sp->grow = False; |
| } |
| ; |
| s4 : /* empty */ { enterscope(mktable(NULL), 0); |
| sp->entry = NULL; |
| sp->mask = True; |
| sp->val = 1; |
| } |
| ; |
| s5 : /* empty */ { } |
| | ',' { } |
| ; |
| s6 : /* empty */ { if (sp->table->level == INTERNAL) |
| transient |= 1; |
| permission = 0; |
| enterscope(mktable(NULL), 0); |
| sp->entry = NULL; |
| sp->table->level = PARAM; |
| } |
| ; |
| store : AUTO { $$ = Sauto; } |
| | REGISTER { $$ = Sregister; } |
| | STATIC { $$ = Sstatic; } |
| | EXPLICIT { $$ = Sexplicit; } |
| | EXTERN { $$ = Sextern; transient = 1; } |
| | TYPEDEF { $$ = Stypedef; } |
| | VIRTUAL { $$ = Svirtual; } |
| | CONST { $$ = Sconst; } |
| | FRIEND { $$ = Sfriend; } |
| | INLINE { $$ = Sinline; } |
| | MUSTUNDERSTAND{ $$ = SmustUnderstand; } |
| | RETURN { $$ = Sreturn; } |
| | '@' { $$ = Sattribute; |
| if (eflag) |
| semwarn("SOAP RPC encoding does not support XML attributes"); |
| } |
| | VOLATILE { $$ = Sextern; transient = -2; } |
| ; |
| constobj: /* empty */ { $$ = Snone; } |
| | CONST { $$ = Sconstobj; } |
| ; |
| abstract: /* empty */ { $$ = Snone; } |
| | '=' LNG { $$ = Sabstract; } |
| ; |
| virtual : /* empty */ { $$ = Snone; } |
| | VIRTUAL { $$ = Svirtual; } |
| ; |
| ptrs : /* empty */ { $$ = tmp = sp->node; } |
| | ptrs '*' { tmp.typ = mkpointer(tmp.typ); |
| tmp.typ->transient = transient; |
| $$ = tmp; |
| } |
| | ptrs '&' { tmp.typ = mkreference(tmp.typ); |
| tmp.typ->transient = transient; |
| $$ = tmp; |
| } |
| ; |
| array : /* empty */ { $$ = tmp; /* tmp is inherited */ |
| } |
| | '[' cexp ']' array |
| { if ($4.typ->type == Tchar) |
| { sprintf(errbuf, "char["SOAP_LONG_FORMAT"] will be encoded as an array of "SOAP_LONG_FORMAT" bytes: use char* for strings", $2.val.i, $2.val.i); |
| semwarn(errbuf); |
| } |
| if ($2.hasval && $2.typ->type == Tint && $2.val.i > 0 && $4.typ->width > 0) |
| $$.typ = mkarray($4.typ, (int) $2.val.i * $4.typ->width); |
| else |
| { $$.typ = mkarray($4.typ, 0); |
| semerror("undetermined array size"); |
| } |
| $$.sto = $4.sto; |
| } |
| | '[' ']' array { $$.typ = mkpointer($3.typ); /* zero size array = pointer */ |
| $$.sto = $3.sto; |
| } |
| ; |
| arrayck : array { if ($1.typ->type == Tstruct || $1.typ->type == Tclass) |
| if (!$1.typ->ref && !$1.typ->transient && !($1.sto & Stypedef)) |
| { sprintf(errbuf, "struct/class '%s' has incomplete type", $1.typ->id->name); |
| semerror(errbuf); |
| } |
| $$ = $1; |
| } |
| ; |
| init : /* empty */ { $$.hasval = False; } |
| | '=' cexp { if ($2.hasval) |
| { $$.typ = $2.typ; |
| $$.hasval = True; |
| $$.val = $2.val; |
| } |
| else |
| { $$.hasval = False; |
| semerror("initialization expression not constant"); |
| } |
| } |
| ; |
| occurs : patt |
| { $$.minOccurs = -1; |
| $$.maxOccurs = 1; |
| $$.pattern = $1; |
| } |
| | patt cint |
| { $$.minOccurs = $2; |
| $$.maxOccurs = 1; |
| $$.pattern = $1; |
| } |
| | patt cint ':' |
| { $$.minOccurs = $2; |
| $$.maxOccurs = 1; |
| $$.pattern = $1; |
| } |
| | patt cint ':' cint |
| { $$.minOccurs = $2; |
| $$.maxOccurs = $4; |
| $$.pattern = $1; |
| } |
| | patt ':' cint |
| { $$.minOccurs = -1; |
| $$.maxOccurs = $3; |
| $$.pattern = $1; |
| } |
| ; |
| patt : /* empty */ { $$ = NULL; } |
| | STR { $$ = $1; } |
| ; |
| cint : LNG { $$ = $1; } |
| | '-' LNG { $$ = -$2; } |
| ; |
| |
| /******************************************************************************\ |
| |
| Expressions |
| |
| \******************************************************************************/ |
| |
| expr : expr ',' expr { $$ = $3; } |
| | cexp { $$ = $1; } |
| ; |
| /* cexp : conditional expression */ |
| cexp : obex '?' qexp ':' cexp |
| { $$.typ = $3.typ; |
| $$.sto = Snone; |
| $$.hasval = False; |
| } |
| | oexp |
| ; |
| /* qexp : true-branch of ? : conditional expression */ |
| qexp : expr { $$ = $1; } |
| ; |
| /* oexp : or-expression */ |
| oexp : obex OR aexp { $$.hasval = False; |
| $$.typ = mkint(); |
| } |
| | aexp { $$ = $1; } |
| ; |
| obex : oexp { $$ = $1; } |
| ; |
| /* aexp : and-expression */ |
| aexp : abex AN rexp { $$.hasval = False; |
| $$.typ = mkint(); |
| } |
| | rexp { $$ = $1; } |
| ; |
| abex : aexp { $$ = $1; } |
| ; |
| /* rexp : relational expression */ |
| rexp : rexp '|' rexp { $$ = iop("|", $1, $3); } |
| | rexp '^' rexp { $$ = iop("^", $1, $3); } |
| | rexp '&' rexp { $$ = iop("&", $1, $3); } |
| | rexp EQ rexp { $$ = relop("==", $1, $3); } |
| | rexp NE rexp { $$ = relop("!=", $1, $3); } |
| | rexp '<' rexp { $$ = relop("<", $1, $3); } |
| | rexp LE rexp { $$ = relop("<=", $1, $3); } |
| | rexp '>' rexp { $$ = relop(">", $1, $3); } |
| | rexp GE rexp { $$ = relop(">=", $1, $3); } |
| | rexp LS rexp { $$ = iop("<<", $1, $3); } |
| | rexp RS rexp { $$ = iop(">>", $1, $3); } |
| | rexp '+' rexp { $$ = op("+", $1, $3); } |
| | rexp '-' rexp { $$ = op("-", $1, $3); } |
| | rexp '*' rexp { $$ = op("*", $1, $3); } |
| | rexp '/' rexp { $$ = op("/", $1, $3); } |
| | rexp '%' rexp { $$ = iop("%", $1, $3); } |
| | lexp { $$ = $1; } |
| ; |
| /* lexp : lvalue kind of expression with optional prefix contructs */ |
| lexp : '!' lexp { if ($2.hasval) |
| $$.val.i = !$2.val.i; |
| $$.typ = $2.typ; |
| $$.hasval = $2.hasval; |
| } |
| | '~' lexp { if ($2.hasval) |
| $$.val.i = ~$2.val.i; |
| $$.typ = $2.typ; |
| $$.hasval = $2.hasval; |
| } |
| | '-' lexp { if ($2.hasval) { |
| if (integer($2.typ)) |
| $$.val.i = -$2.val.i; |
| else if (real($2.typ)) |
| $$.val.r = -$2.val.r; |
| else typerror("string?"); |
| } |
| $$.typ = $2.typ; |
| $$.hasval = $2.hasval; |
| } |
| | '+' lexp { $$ = $2; } |
| | '*' lexp { if ($2.typ->type == Tpointer) { |
| $$.typ = (Tnode*) $2.typ->ref; |
| } else |
| typerror("dereference of non-pointer type"); |
| $$.sto = Snone; |
| $$.hasval = False; |
| } |
| | '&' lexp { $$.typ = mkpointer($2.typ); |
| $$.sto = Snone; |
| $$.hasval = False; |
| } |
| | SIZEOF '(' texp ')' |
| { $$.hasval = True; |
| $$.typ = mkint(); |
| $$.val.i = $3.typ->width; |
| } |
| | pexp { $$ = $1; } |
| ; |
| /* pexp : primitive expression with optional postfix constructs */ |
| pexp : '(' expr ')' { $$ = $2; } |
| | ID { if ((p = enumentry($1)) == (Entry*) 0) |
| p = undefined($1); |
| else |
| $$.hasval = True; |
| $$.typ = p->info.typ; |
| $$.val = p->info.val; |
| } |
| | LNG { $$.typ = mkint(); |
| $$.hasval = True; |
| $$.val.i = $1; |
| } |
| | null { $$.typ = mkint(); |
| $$.hasval = True; |
| $$.val.i = 0; |
| } |
| | DBL { $$.typ = mkfloat(); |
| $$.hasval = True; |
| $$.val.r = $1; |
| } |
| | CHR { $$.typ = mkchar(); |
| $$.hasval = True; |
| $$.val.i = $1; |
| } |
| | STR { $$.typ = mkstring(); |
| $$.hasval = True; |
| $$.val.s = $1; |
| } |
| | CFALSE { $$.typ = mkbool(); |
| $$.hasval = True; |
| $$.val.i = 0; |
| } |
| | CTRUE { $$.typ = mkbool(); |
| $$.hasval = True; |
| $$.val.i = 1; |
| } |
| ; |
| |
| %% |
| |
| /* |
| * ??? |
| */ |
| int |
| yywrap() |
| { return 1; |
| } |
| |
| /******************************************************************************\ |
| |
| Support routines |
| |
| \******************************************************************************/ |
| |
| static Node |
| op(const char *op, Node p, Node q) |
| { Node r; |
| Tnode *typ; |
| r.typ = p.typ; |
| r.sto = Snone; |
| if (p.hasval && q.hasval) { |
| if (integer(p.typ) && integer(q.typ)) |
| switch (op[0]) { |
| case '|': r.val.i = p.val.i | q.val.i; break; |
| case '^': r.val.i = p.val.i ^ q.val.i; break; |
| case '&': r.val.i = p.val.i & q.val.i; break; |
| case '<': r.val.i = p.val.i << q.val.i; break; |
| case '>': r.val.i = p.val.i >> q.val.i; break; |
| case '+': r.val.i = p.val.i + q.val.i; break; |
| case '-': r.val.i = p.val.i - q.val.i; break; |
| case '*': r.val.i = p.val.i * q.val.i; break; |
| case '/': r.val.i = p.val.i / q.val.i; break; |
| case '%': r.val.i = p.val.i % q.val.i; break; |
| default: typerror(op); |
| } |
| else if (real(p.typ) && real(q.typ)) |
| switch (op[0]) { |
| case '+': r.val.r = p.val.r + q.val.r; break; |
| case '-': r.val.r = p.val.r - q.val.r; break; |
| case '*': r.val.r = p.val.r * q.val.r; break; |
| case '/': r.val.r = p.val.r / q.val.r; break; |
| default: typerror(op); |
| } |
| else semerror("illegal constant operation"); |
| r.hasval = True; |
| } else { |
| typ = mgtype(p.typ, q.typ); |
| r.hasval = False; |
| } |
| return r; |
| } |
| |
| static Node |
| iop(const char *iop, Node p, Node q) |
| { if (integer(p.typ) && integer(q.typ)) |
| return op(iop, p, q); |
| typerror("integer operands only"); |
| return p; |
| } |
| |
| static Node |
| relop(const char *op, Node p, Node q) |
| { Node r; |
| Tnode *typ; |
| r.typ = mkint(); |
| r.sto = Snone; |
| r.hasval = False; |
| if (p.typ->type != Tpointer || p.typ != q.typ) |
| typ = mgtype(p.typ, q.typ); |
| return r; |
| } |
| |
| /******************************************************************************\ |
| |
| Scope management |
| |
| \******************************************************************************/ |
| |
| /* |
| mkscope - initialize scope stack with a new table and offset |
| */ |
| static void |
| mkscope(Table *table, int offset) |
| { sp = stack-1; |
| enterscope(table, offset); |
| } |
| |
| /* |
| enterscope - enter a new scope by pushing a new table and offset on the stack |
| */ |
| static void |
| enterscope(Table *table, int offset) |
| { if (++sp == stack+MAXNEST) |
| execerror("maximum scope depth exceeded"); |
| sp->table = table; |
| sp->val = 0; |
| sp->offset = offset; |
| sp->grow = True; /* by default, offset grows */ |
| sp->mask = False; |
| } |
| |
| /* |
| exitscope - exit a scope by popping the table and offset from the stack |
| */ |
| static void |
| exitscope() |
| { check(sp-- != stack, "exitscope() has no matching enterscope()"); |
| } |
| |
| /******************************************************************************\ |
| |
| Undefined symbol |
| |
| \******************************************************************************/ |
| |
| static Entry* |
| undefined(Symbol *sym) |
| { Entry *p; |
| sprintf(errbuf, "undefined identifier '%s'", sym->name); |
| semwarn(errbuf); |
| p = enter(sp->table, sym); |
| p->level = GLOBAL; |
| p->info.typ = mkint(); |
| p->info.sto = Sextern; |
| p->info.hasval = False; |
| return p; |
| } |
| |
| /* |
| mgtype - return most general type among two numerical types |
| */ |
| Tnode* |
| mgtype(Tnode *typ1, Tnode *typ2) |
| { if (numeric(typ1) && numeric(typ2)) { |
| if (typ1->type < typ2->type) |
| return typ2; |
| } else typerror("non-numeric type"); |
| return typ1; |
| } |
| |
| /******************************************************************************\ |
| |
| Type checks |
| |
| \******************************************************************************/ |
| |
| static int |
| integer(Tnode *typ) |
| { switch (typ->type) { |
| case Tchar: |
| case Tshort: |
| case Tint: |
| case Tlong: return True; |
| } |
| return False; |
| } |
| |
| static int |
| real(Tnode *typ) |
| { switch (typ->type) { |
| case Tfloat: |
| case Tdouble: return True; |
| } |
| return False; |
| } |
| |
| static int |
| numeric(Tnode *typ) |
| { return integer(typ) || real(typ); |
| } |
| |
| static int |
| pointer(Tnode *typ) |
| { return typ->type == Tpointer; |
| } |
| |
| static void |
| add_fault(Table *gt) |
| { Table *t; |
| Entry *p1, *p2, *p3, *p4; |
| Symbol *s1, *s2, *s3, *s4; |
| s1 = lookup("SOAP_ENV__Code"); |
| p1 = entry(classtable, s1); |
| if (!p1 || !p1->info.typ->ref) |
| { t = mktable((Table*)0); |
| if (!p1) |
| { p1 = enter(classtable, s1); |
| p1->info.typ = mkstruct(t, 3*4); |
| p1->info.typ->id = s1; |
| } |
| else |
| p1->info.typ->ref = t; |
| p2 = enter(t, lookup("SOAP_ENV__Value")); |
| p2->info.typ = qname; |
| p2->info.minOccurs = 0; |
| p2 = enter(t, lookup("SOAP_ENV__Subcode")); |
| p2->info.typ = mkpointer(p1->info.typ); |
| p2->info.minOccurs = 0; |
| } |
| s2 = lookup("SOAP_ENV__Detail"); |
| p2 = entry(classtable, s2); |
| if (!p2 || !p2->info.typ->ref) |
| { t = mktable((Table*)0); |
| if (!p2) |
| { p2 = enter(classtable, s2); |
| p2->info.typ = mkstruct(t, 3*4); |
| p2->info.typ->id = s2; |
| } |
| else |
| p2->info.typ->ref = t; |
| p3 = enter(t, lookup("__type")); |
| p3->info.typ = mkint(); |
| p3->info.minOccurs = 0; |
| p3 = enter(t, lookup("fault")); |
| p3->info.typ = mkpointer(mkvoid()); |
| p3->info.minOccurs = 0; |
| p3 = enter(t, lookup("__any")); |
| p3->info.typ = xml; |
| p3->info.minOccurs = 0; |
| custom_fault = 0; |
| } |
| s4 = lookup("SOAP_ENV__Reason"); |
| p4 = entry(classtable, s4); |
| if (!p4 || !p4->info.typ->ref) |
| { t = mktable((Table*)0); |
| if (!p4) |
| { p4 = enter(classtable, s4); |
| p4->info.typ = mkstruct(t, 4); |
| p4->info.typ->id = s4; |
| } |
| else |
| p4->info.typ->ref = t; |
| p3 = enter(t, lookup("SOAP_ENV__Text")); |
| p3->info.typ = mkstring(); |
| p3->info.minOccurs = 0; |
| } |
| s3 = lookup("SOAP_ENV__Fault"); |
| p3 = entry(classtable, s3); |
| if (!p3) |
| { t = mktable(NULL); |
| p3 = enter(classtable, s3); |
| p3->info.typ = mkstruct(t, 9*4); |
| p3->info.typ->id = s3; |
| p3 = enter(t, lookup("faultcode")); |
| p3->info.typ = qname; |
| p3->info.minOccurs = 0; |
| p3 = enter(t, lookup("faultstring")); |
| p3->info.typ = mkstring(); |
| p3->info.minOccurs = 0; |
| p3 = enter(t, lookup("faultactor")); |
| p3->info.typ = mkstring(); |
| p3->info.minOccurs = 0; |
| p3 = enter(t, lookup("detail")); |
| p3->info.typ = mkpointer(p2->info.typ); |
| p3->info.minOccurs = 0; |
| p3 = enter(t, s1); |
| p3->info.typ = mkpointer(p1->info.typ); |
| p3->info.minOccurs = 0; |
| p3 = enter(t, s4); |
| p3->info.typ = mkpointer(p4->info.typ); |
| p3->info.minOccurs = 0; |
| p3 = enter(t, lookup("SOAP_ENV__Node")); |
| p3->info.typ = mkstring(); |
| p3->info.minOccurs = 0; |
| p3 = enter(t, lookup("SOAP_ENV__Role")); |
| p3->info.typ = mkstring(); |
| p3->info.minOccurs = 0; |
| p3 = enter(t, lookup("SOAP_ENV__Detail")); |
| p3->info.typ = mkpointer(p2->info.typ); |
| p3->info.minOccurs = 0; |
| } |
| } |
| |
| static void |
| add_XML() |
| { Symbol *s = lookup("_XML"); |
| int tmp = imports; |
| imports = 0; |
| p = enter(typetable, s); |
| xml = p->info.typ = mksymtype(mkstring(), s); |
| p->info.sto = Stypedef; |
| imports = tmp; |
| } |
| |
| static void |
| add_qname() |
| { Symbol *s = lookup("_QName"); |
| int tmp = imports; |
| p = enter(typetable, s); |
| qname = p->info.typ = mksymtype(mkstring(), s); |
| qname->imports = 0; |
| p->info.sto = Stypedef; |
| imports = tmp; |
| } |
| |
| static void |
| add_header(Table *gt) |
| { Table *t; |
| Entry *p; |
| Symbol *s = lookup("SOAP_ENV__Header"); |
| p = entry(classtable, s); |
| if (!p) |
| { t = mktable((Table*)0); |
| p = enter(t, lookup("dummy")); |
| p->info.typ = mkpointer(mkvoid()); |
| p = enter(classtable, s); |
| p->info.typ = mkstruct(t, 4); |
| p->info.typ->id = s; |
| custom_header = 0; |
| } |
| } |
| |
| static void |
| add_response(Entry *fun, Entry *ret) |
| { Table *t; |
| Entry *p, *q; |
| Symbol *s; |
| int n = strlen(fun->sym->name); |
| char *r = (char*)emalloc(n+9); |
| strcpy(r, fun->sym->name); |
| strcat(r, "Response"); |
| if (!(s = lookup(r))) |
| s = install(r, ID); |
| free(r); |
| t = mktable((Table*)0); |
| q = enter(t, ret->sym); |
| q->info = ret->info; |
| if (q->info.typ->type == Treference) |
| q->info.typ = (Tnode*)q->info.typ->ref; |
| p = enter(classtable, s); |
| p->info.typ = mkstruct(t, 4); |
| p->info.typ->id = s; |
| fun->info.typ->response = p; |
| } |
| |
| static void |
| add_result(Tnode *typ) |
| { Entry *p; |
| if (!typ->ref || !((Tnode*)typ->ref)->ref) |
| { semwarn("response struct/class must be declared before used in function prototype"); |
| return; |
| } |
| for (p = ((Table*)((Tnode*)typ->ref)->ref)->list; p; p = p->next) |
| if (p->info.sto & Sreturn) |
| return; |
| p = ((Table*)((Tnode*)typ->ref)->ref)->list; |
| if (p) |
| p->info.sto = (Storage)((int)p->info.sto | (int)Sreturn); |
| } |