comparison GEMBASSY-1.0.3/gsoap/src/soapcpp2_yacc.y @ 2:8947fca5f715 draft default tip

Uploaded
author ktnyt
date Fri, 26 Jun 2015 05:21:44 -0400
parents 84a17b3fad1f
children
comparison
equal deleted inserted replaced
1:84a17b3fad1f 2:8947fca5f715
1 /*
2 soapcpp2_yacc.y
3
4 Yacc/Bison grammar.
5
6 Build notes:
7
8 1. Bison 1.6 is known to crash on Win32 systems if YYINITDEPTH is too
9 small Compile with -DYYINITDEPTH=5000
10
11 2. This grammar has one shift/reduce conflict related to the use of a
12 class declaration with a base class (e.g. class Y : public X) and the
13 use of a maxOccurs (class Y :10). Internally the conflict is resolved
14 in favor of a shift by Bison/Yacc, which leads to the correct parsing
15 behavior. Therefore, the warning can be ignored. If this leads to an
16 error, then please enable the following directive (around line 121):
17
18 %expect 1 // Bison: ignore one shift/reduce conflict
19
20 --------------------------------------------------------------------------------
21 gSOAP XML Web services tools
22 Copyright (C) 2000-2011, Robert van Engelen, Genivia Inc. All Rights Reserved.
23 This part of the software is released under ONE of the following licenses:
24 GPL or Genivia's license for commercial use.
25 --------------------------------------------------------------------------------
26 GPL license.
27
28 This program is free software; you can redistribute it and/or modify it under
29 the terms of the GNU General Public License as published by the Free Software
30 Foundation; either version 2 of the License, or (at your option) any later
31 version.
32
33 This program is distributed in the hope that it will be useful, but WITHOUT ANY
34 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
35 PARTICULAR PURPOSE. See the GNU General Public License for more details.
36
37 You should have received a copy of the GNU General Public License along with
38 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
39 Place, Suite 330, Boston, MA 02111-1307 USA
40
41 Author contact information:
42 engelen@genivia.com / engelen@acm.org
43
44 This program is released under the GPL with the additional exemption that
45 compiling, linking, and/or using OpenSSL is allowed.
46 --------------------------------------------------------------------------------
47 A commercial use license is available from Genivia, Inc., contact@genivia.com
48 --------------------------------------------------------------------------------
49 */
50
51 %{
52
53 #include "soapcpp2.h"
54
55 #ifdef WIN32
56 #ifndef __STDC__
57 #define __STDC__
58 #endif
59 #define YYINCLUDED_STDLIB_H
60 #ifdef WIN32_WITHOUT_SOLARIS_FLEX
61 extern int soapcpp2lex(void);
62 #else
63 extern int yylex(void);
64 #endif
65 #else
66 extern int yylex(void);
67 #endif
68
69 extern int is_XML(Tnode*);
70
71 #define MAXNEST 16 /* max. nesting depth of scopes */
72
73 struct Scope
74 { Table *table;
75 Entry *entry;
76 Node node;
77 LONG64 val;
78 int offset;
79 Bool grow; /* true if offset grows with declarations */
80 Bool mask; /* true if enum is mask */
81 } stack[MAXNEST], /* stack of tables and offsets */
82 *sp; /* current scope stack pointer */
83
84 Table *classtable = (Table*)0,
85 *enumtable = (Table*)0,
86 *typetable = (Table*)0,
87 *booltable = (Table*)0,
88 *templatetable = (Table*)0;
89
90 char *namespaceid = NULL;
91 int transient = 0;
92 int permission = 0;
93 int custom_header = 1;
94 int custom_fault = 1;
95 Pragma *pragmas = NULL;
96 Tnode *qname = NULL;
97 Tnode *xml = NULL;
98
99 /* function prototypes for support routine section */
100 static Entry *undefined(Symbol*);
101 static Tnode *mgtype(Tnode*, Tnode*);
102 static Node op(const char*, Node, Node), iop(const char*, Node, Node), relop(const char*, Node, Node);
103 static void mkscope(Table*, int), enterscope(Table*, int), exitscope(void);
104 static int integer(Tnode*), real(Tnode*), numeric(Tnode*);
105 static void add_soap(void), add_XML(void), add_qname(void), add_header(Table*), add_fault(Table*), add_response(Entry*, Entry*), add_result(Tnode*);
106 extern char *c_storage(Storage), *c_type(Tnode*), *c_ident(Tnode*);
107 extern int is_primitive_or_string(Tnode*), is_stdstr(Tnode*), is_binary(Tnode*), is_external(Tnode*), is_mutable(Tnode*), has_attachment(Tnode*);
108
109 /* Temporaries used in semantic rules */
110 int i;
111 char *s, *s1, *s2;
112 Symbol *sym;
113 Entry *p, *q;
114 Tnode *t;
115 Node tmp, c;
116 Pragma **pp;
117
118 %}
119
120 /* We expect one shift-reduce conflict, see build notes in the header above */
121 /* %expect 1 */ /* directive is not compatible with Yacc */
122 /* If Yacc complains then remove the line above to allow Yacc to proceed */
123
124 %union
125 { Symbol *sym;
126 LONG64 i;
127 double r;
128 char c;
129 char *s;
130 Tnode *typ;
131 Storage sto;
132 Node rec;
133 Entry *e;
134 }
135
136 /* pragmas */
137 %token <s> PRAGMA
138 /* keywords */
139 %token <sym> AUTO DOUBLE INT STRUCT
140 %token <sym> BREAK ELSE LONG SWITCH
141 %token <sym> CASE ENUM REGISTER TYPEDEF
142 %token <sym> CHAR EXTERN RETURN UNION
143 %token <sym> CONST FLOAT SHORT UNSIGNED
144 %token <sym> CONTINUE FOR SIGNED VOID
145 %token <sym> DEFAULT GOTO SIZEOF VOLATILE
146 %token <sym> DO IF STATIC WHILE
147 %token <sym> CLASS PRIVATE PROTECTED PUBLIC
148 %token <sym> VIRTUAL INLINE OPERATOR LLONG
149 %token <sym> BOOL CFALSE CTRUE WCHAR
150 %token <sym> TIME USING NAMESPACE ULLONG
151 %token <sym> MUSTUNDERSTAND SIZE FRIEND
152 %token <sym> TEMPLATE EXPLICIT TYPENAME
153 %token <sym> RESTRICT null
154 %token <sym> UCHAR USHORT UINT ULONG
155 /* */
156 %token NONE
157 /* identifiers (TYPE = typedef identifier) */
158 %token <sym> ID LAB TYPE
159 /* constants */
160 %token <i> LNG
161 %token <r> DBL
162 %token <c> CHR
163 %token <s> TAG STR
164 /* types and related */
165 %type <typ> type
166 %type <sto> store virtual constobj abstract
167 %type <e> fname struct class base enum
168 %type <sym> id arg name
169 %type <s> tag patt
170 %type <i> cint
171 /* expressions and statements */
172 %type <rec> expr cexp oexp obex aexp abex rexp lexp pexp init spec tspec ptrs array arrayck texp qexp occurs
173 /* terminals */
174 %left ','
175 %right '=' PA NA TA DA MA AA XA OA LA RA /* += -= *= /= %= &= ^= |= <<= >>= */
176 %right '?'
177 %right ':'
178 %left OR /* || */
179 %left AN /* && */
180 %left '|'
181 %left '^'
182 %left '&'
183 %left EQ NE /* == != */
184 %left '<' LE '>' GE /* <= >= */
185 %left LS RS /* << >> */
186 %left '+' '-'
187 %left '*' '/' '%'
188 %left AR /* -> */
189 %token PP NN /* ++ -- */
190
191 %%
192
193 /******************************************************************************\
194
195 Program syntax
196
197 \******************************************************************************/
198
199 prog : s1 exts { if (lflag)
200 { custom_header = 0;
201 custom_fault = 0;
202 }
203 else
204 { add_header(sp->table);
205 add_fault(sp->table);
206 }
207 compile(sp->table);
208 freetable(classtable);
209 freetable(enumtable);
210 freetable(typetable);
211 freetable(booltable);
212 freetable(templatetable);
213 }
214 ;
215 s1 : /* empty */ { classtable = mktable((Table*)0);
216 enumtable = mktable((Table*)0);
217 typetable = mktable((Table*)0);
218 booltable = mktable((Table*)0);
219 templatetable = mktable((Table*)0);
220 p = enter(booltable, lookup("false"));
221 p->info.typ = mkint();
222 p->info.val.i = 0;
223 p = enter(booltable, lookup("true"));
224 p->info.typ = mkint();
225 p->info.val.i = 1;
226 mkscope(mktable(mktable((Table*)0)), 0);
227 }
228 ;
229 exts : NAMESPACE ID '{' exts1 '}'
230 { namespaceid = $2->name; }
231 | exts1 { }
232 ;
233 exts1 : /* empty */ { add_soap();
234 add_qname();
235 add_XML();
236 }
237 | exts1 ext { }
238 ;
239 ext : dclrs ';' { }
240 | pragma { }
241 | error ';' { synerror("input before ; skipped");
242 while (sp > stack)
243 { freetable(sp->table);
244 exitscope();
245 }
246 yyerrok;
247 }
248 | t1 { }
249 | t2 { }
250 ;
251 pragma : PRAGMA { if ($1[1] >= 'a' && $1[1] <= 'z')
252 { for (pp = &pragmas; *pp; pp = &(*pp)->next)
253 ;
254 *pp = (Pragma*)emalloc(sizeof(Pragma));
255 (*pp)->pragma = (char*)emalloc(strlen($1)+1);
256 strcpy((*pp)->pragma, $1);
257 (*pp)->next = NULL;
258 }
259 else if ((i = atoi($1+2)) > 0)
260 yylineno = i;
261 else
262 { sprintf(errbuf, "directive '%s' ignored (use #import to import files)", $1);
263 semwarn(errbuf);
264 }
265 }
266 ;
267
268 /******************************************************************************\
269
270 Declarations
271
272 \******************************************************************************/
273
274 decls : /* empty */ { transient &= ~6;
275 permission = 0;
276 }
277 | dclrs ';' decls
278 { }
279 | PRIVATE ':' t3 decls
280 { }
281 | PROTECTED ':' t4 decls
282 { }
283 | PUBLIC ':' t5 decls
284 { }
285 | t1 decls t2 decls
286 { }
287 | error ';' { synerror("declaration expected"); yyerrok; }
288 ;
289 t1 : '[' { transient |= 1;
290 }
291 ;
292 t2 : ']' { transient &= ~1;
293 }
294 ;
295 t3 : { permission = Sprivate;
296 }
297 ;
298 t4 : { permission = Sprotected;
299 }
300 ;
301 t5 : { permission = 0;
302 }
303 ;
304 dclrs : spec { }
305 | spec dclr { }
306 | spec fdclr func
307 { }
308 | constr func { }
309 | destr func { }
310 | dclrs ',' dclr{ }
311 | dclrs ',' fdclr func
312 { }
313 ;
314 dclr : ptrs ID arrayck tag occurs init
315 { if (($3.sto & Stypedef) && sp->table->level == GLOBAL)
316 { if (($3.typ->type != Tstruct && $3.typ->type != Tunion && $3.typ->type != Tenum) || strcmp($2->name, $3.typ->id->name))
317 { p = enter(typetable, $2);
318 p->info.typ = mksymtype($3.typ, $2);
319 if ($3.sto & Sextern)
320 p->info.typ->transient = -1;
321 else
322 p->info.typ->transient = $3.typ->transient;
323 p->info.sto = $3.sto;
324 p->info.typ->pattern = $5.pattern;
325 p->info.typ->minLength = $5.minLength;
326 p->info.typ->maxLength = $5.maxLength;
327 }
328 $2->token = TYPE;
329 }
330 else
331 { p = enter(sp->table, $2);
332 p->tag = $4;
333 p->info.typ = $3.typ;
334 p->info.sto = (Storage)((int)$3.sto | permission);
335 if ($6.hasval)
336 { p->info.hasval = True;
337 switch ($3.typ->type)
338 { case Tchar:
339 case Tuchar:
340 case Tshort:
341 case Tushort:
342 case Tint:
343 case Tuint:
344 case Tlong:
345 case Tulong:
346 case Tllong:
347 case Tullong:
348 case Tenum:
349 case Ttime:
350 if ($6.typ->type == Tint || $6.typ->type == Tchar || $6.typ->type == Tenum)
351 sp->val = p->info.val.i = $6.val.i;
352 else
353 { semerror("type error in initialization constant");
354 p->info.hasval = False;
355 }
356 break;
357 case Tfloat:
358 case Tdouble:
359 case Tldouble:
360 if ($6.typ->type == Tfloat || $6.typ->type == Tdouble || $6.typ->type == Tldouble)
361 p->info.val.r = $6.val.r;
362 else if ($6.typ->type == Tint)
363 p->info.val.r = (double)$6.val.i;
364 else
365 { semerror("type error in initialization constant");
366 p->info.hasval = False;
367 }
368 break;
369 default:
370 if ($3.typ->type == Tpointer
371 && (((Tnode*)$3.typ->ref)->type == Tchar || ((Tnode*)$3.typ->ref)->type == Twchar)
372 && $6.typ->type == Tpointer
373 && ((Tnode*)$6.typ->ref)->type == Tchar)
374 p->info.val.s = $6.val.s;
375 else if (bflag
376 && $3.typ->type == Tarray
377 && ((Tnode*)$3.typ->ref)->type == Tchar
378 && $6.typ->type == Tpointer
379 && ((Tnode*)$6.typ->ref)->type == Tchar)
380 { if ($3.typ->width / ((Tnode*)$3.typ->ref)->width - 1 < strlen($6.val.s))
381 { semerror("char[] initialization constant too long");
382 p->info.val.s = "";
383 }
384
385 else
386 p->info.val.s = $6.val.s;
387 }
388 else if ($3.typ->type == Tpointer
389 && (((Tnode*)$3.typ->ref)->id == lookup("std::string") || ((Tnode*)$3.typ->ref)->id == lookup("std::wstring")))
390 p->info.val.s = $6.val.s;
391 else if ($3.typ->id == lookup("std::string") || $3.typ->id == lookup("std::wstring"))
392 p->info.val.s = $6.val.s;
393 else if ($3.typ->type == Tpointer
394 && $6.typ->type == Tint
395 && $6.val.i == 0)
396 p->info.val.i = 0;
397 else
398 { semerror("type error in initialization constant");
399 p->info.hasval = False;
400 }
401 break;
402 }
403 }
404 else
405 p->info.val.i = sp->val;
406 if ($5.minOccurs < 0)
407 { if ($6.hasval || ($3.sto & Sattribute) || $3.typ->type == Tpointer || $3.typ->type == Ttemplate || !strncmp($2->name, "__size", 6))
408 p->info.minOccurs = 0;
409 else
410 p->info.minOccurs = 1;
411 }
412 else
413 p->info.minOccurs = $5.minOccurs;
414 p->info.maxOccurs = $5.maxOccurs;
415 if (sp->mask)
416 sp->val <<= 1;
417 else
418 sp->val++;
419 p->info.offset = sp->offset;
420 if ($3.sto & Sextern)
421 p->level = GLOBAL;
422 else if ($3.sto & Stypedef)
423 ;
424 else if (sp->grow)
425 sp->offset += p->info.typ->width;
426 else if (p->info.typ->width > sp->offset)
427 sp->offset = p->info.typ->width;
428 }
429 sp->entry = p;
430 }
431 ;
432 fdclr : ptrs name { if ($1.sto & Stypedef)
433 { sprintf(errbuf, "invalid typedef qualifier for '%s'", $2->name);
434 semwarn(errbuf);
435 }
436 p = enter(sp->table, $2);
437 p->info.typ = $1.typ;
438 p->info.sto = $1.sto;
439 p->info.hasval = False;
440 p->info.offset = sp->offset;
441 if (sp->grow)
442 sp->offset += p->info.typ->width;
443 else if (p->info.typ->width > sp->offset)
444 sp->offset = p->info.typ->width;
445 sp->entry = p;
446 }
447 ;
448 id : ID { $$ = $1; }
449 | TYPE { $$ = $1; }
450 ;
451 name : ID { $$ = $1; }
452 | OPERATOR '!' { $$ = lookup("operator!"); }
453 | OPERATOR '~' { $$ = lookup("operator~"); }
454 | OPERATOR '=' { $$ = lookup("operator="); }
455 | OPERATOR PA { $$ = lookup("operator+="); }
456 | OPERATOR NA { $$ = lookup("operator-="); }
457 | OPERATOR TA { $$ = lookup("operator*="); }
458 | OPERATOR DA { $$ = lookup("operator/="); }
459 | OPERATOR MA { $$ = lookup("operator%="); }
460 | OPERATOR AA { $$ = lookup("operator&="); }
461 | OPERATOR XA { $$ = lookup("operator^="); }
462 | OPERATOR OA { $$ = lookup("operator|="); }
463 | OPERATOR LA { $$ = lookup("operator<<="); }
464 | OPERATOR RA { $$ = lookup("operator>>="); }
465 | OPERATOR OR { $$ = lookup("operator||"); }
466 | OPERATOR AN { $$ = lookup("operator&&"); }
467 | OPERATOR '|' { $$ = lookup("operator|"); }
468 | OPERATOR '^' { $$ = lookup("operator^"); }
469 | OPERATOR '&' { $$ = lookup("operator&"); }
470 | OPERATOR EQ { $$ = lookup("operator=="); }
471 | OPERATOR NE { $$ = lookup("operator!="); }
472 | OPERATOR '<' { $$ = lookup("operator<"); }
473 | OPERATOR LE { $$ = lookup("operator<="); }
474 | OPERATOR '>' { $$ = lookup("operator>"); }
475 | OPERATOR GE { $$ = lookup("operator>="); }
476 | OPERATOR LS { $$ = lookup("operator<<"); }
477 | OPERATOR RS { $$ = lookup("operator>>"); }
478 | OPERATOR '+' { $$ = lookup("operator+"); }
479 | OPERATOR '-' { $$ = lookup("operator-"); }
480 | OPERATOR '*' { $$ = lookup("operator*"); }
481 | OPERATOR '/' { $$ = lookup("operator/"); }
482 | OPERATOR '%' { $$ = lookup("operator%"); }
483 | OPERATOR PP { $$ = lookup("operator++"); }
484 | OPERATOR NN { $$ = lookup("operator--"); }
485 | OPERATOR AR { $$ = lookup("operator->"); }
486 | OPERATOR'['']'{ $$ = lookup("operator[]"); }
487 | OPERATOR'('')'{ $$ = lookup("operator()"); }
488 | OPERATOR texp { s1 = c_storage($2.sto);
489 s2 = c_type($2.typ);
490 s = (char*)emalloc(strlen(s1) + strlen(s2) + 10);
491 strcpy(s, "operator ");
492 strcat(s, s1);
493 strcat(s, s2);
494 $$ = lookup(s);
495 if (!$$)
496 $$ = install(s, ID);
497 }
498 ;
499 constr : TYPE { if (!(p = entry(classtable, $1)))
500 semerror("invalid constructor");
501 sp->entry = enter(sp->table, $1);
502 sp->entry->info.typ = mknone();
503 sp->entry->info.sto = Snone;
504 sp->entry->info.offset = sp->offset;
505 sp->node.typ = mkvoid();
506 sp->node.sto = Snone;
507 }
508 ;
509 destr : virtual '~' TYPE
510 { if (!(p = entry(classtable, $3)))
511 semerror("invalid destructor");
512 s = (char*)emalloc(strlen($3->name) + 2);
513 strcpy(s, "~");
514 strcat(s, $3->name);
515 sym = lookup(s);
516 if (!sym)
517 sym = install(s, ID);
518 sp->entry = enter(sp->table, sym);
519 sp->entry->info.typ = mknone();
520 sp->entry->info.sto = $1;
521 sp->entry->info.offset = sp->offset;
522 sp->node.typ = mkvoid();
523 sp->node.sto = Snone;
524 }
525 ;
526 func : fname '(' s6 fargso ')' constobj abstract
527 { if ($1->level == GLOBAL)
528 { if (!($1->info.sto & Sextern) && sp->entry && sp->entry->info.typ->type == Tpointer && ((Tnode*)sp->entry->info.typ->ref)->type == Tchar)
529 { 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);
530 semwarn(errbuf);
531 }
532 if ($1->info.sto & Sextern)
533 $1->info.typ = mkmethod($1->info.typ, sp->table);
534 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)))
535 { if ($1->info.typ->type == Tint)
536 { sp->entry->info.sto = (Storage)((int)sp->entry->info.sto | (int)Sreturn);
537 $1->info.typ = mkfun(sp->entry);
538 $1->info.typ->id = $1->sym;
539 if (!is_transient(sp->entry->info.typ))
540 { if (!is_response(sp->entry->info.typ))
541 { if (!is_XML(sp->entry->info.typ))
542 add_response($1, sp->entry);
543 }
544 else
545 add_result(sp->entry->info.typ);
546 }
547 }
548 else
549 { sprintf(errbuf, "return type of remote method function prototype '%s' must be integer", $1->sym->name);
550 semerror(errbuf);
551 }
552 }
553 else
554 { sprintf(errbuf, "last output parameter of remote method function prototype '%s' is a return parameter and must be a pointer or reference, or use %s(..., void) for one-way sends", $1->sym->name, $1->sym->name);
555 semerror(errbuf);
556 }
557 if (!($1->info.sto & Sextern))
558 { unlinklast(sp->table);
559 if ((p = entry(classtable, $1->sym)))
560 { if (p->info.typ->ref)
561 { sprintf(errbuf, "remote method name clash: struct/class '%s' already declared at line %d", $1->sym->name, p->lineno);
562 semerror(errbuf);
563 }
564 else
565 { p->info.typ->ref = sp->table;
566 p->info.typ->width = sp->offset;
567 }
568 }
569 else
570 { p = enter(classtable, $1->sym);
571 p->info.typ = mkstruct(sp->table, sp->offset);
572 p->info.typ->id = $1->sym;
573 }
574 }
575 }
576 else if ($1->level == INTERNAL)
577 { $1->info.typ = mkmethod($1->info.typ, sp->table);
578 $1->info.sto = (Storage)((int)$1->info.sto | (int)$6 | (int)$7);
579 transient &= ~1;
580 }
581 exitscope();
582 }
583 ;
584 fname : { $$ = sp->entry; }
585 ;
586 fargso : /* empty */ { }
587 | fargs { }
588 ;
589 fargs : farg { }
590 | farg ',' fargs{ }
591 ;
592 farg : tspec ptrs arg arrayck occurs init
593 { if ($4.sto & Stypedef)
594 semwarn("typedef in function argument");
595 p = enter(sp->table, $3);
596 p->info.typ = $4.typ;
597 p->info.sto = $4.sto;
598 if ($5.minOccurs < 0)
599 { if ($6.hasval || ($4.sto & Sattribute) || $4.typ->type == Tpointer)
600 p->info.minOccurs = 0;
601 else
602 p->info.minOccurs = 1;
603 }
604 else
605 p->info.minOccurs = $5.minOccurs;
606 p->info.maxOccurs = $5.maxOccurs;
607 if ($6.hasval)
608 { p->info.hasval = True;
609 switch ($4.typ->type)
610 { case Tchar:
611 case Tuchar:
612 case Tshort:
613 case Tushort:
614 case Tint:
615 case Tuint:
616 case Tlong:
617 case Tulong:
618 case Tenum:
619 case Ttime:
620 if ($6.typ->type == Tint || $6.typ->type == Tchar || $6.typ->type == Tenum)
621 sp->val = p->info.val.i = $6.val.i;
622 else
623 { semerror("type error in initialization constant");
624 p->info.hasval = False;
625 }
626 break;
627 case Tfloat:
628 case Tdouble:
629 case Tldouble:
630 if ($6.typ->type == Tfloat || $6.typ->type == Tdouble || $6.typ->type == Tldouble)
631 p->info.val.r = $6.val.r;
632 else if ($6.typ->type == Tint)
633 p->info.val.r = (double)$6.val.i;
634 else
635 { semerror("type error in initialization constant");
636 p->info.hasval = False;
637 }
638 break;
639 default:
640 if ($4.typ->type == Tpointer
641 && (((Tnode*)$4.typ->ref)->type == Tchar || ((Tnode*)$4.typ->ref)->type == Twchar)
642 && $6.typ->type == Tpointer
643 && ((Tnode*)$6.typ->ref)->type == Tchar)
644 p->info.val.s = $6.val.s;
645 else if ($4.typ->type == Tpointer
646 && (((Tnode*)$4.typ->ref)->id == lookup("std::string") || ((Tnode*)$4.typ->ref)->id == lookup("std::wstring")))
647 p->info.val.s = $6.val.s;
648 else if ($4.typ->id == lookup("std::string") || $4.typ->id == lookup("std::wstring"))
649 p->info.val.s = $6.val.s;
650 else if ($4.typ->type == Tpointer
651 && $6.typ->type == Tint
652 && $6.val.i == 0)
653 p->info.val.i = 0;
654 else
655 { semerror("type error in initialization constant");
656 p->info.hasval = False;
657 }
658 break;
659 }
660 }
661 p->info.offset = sp->offset;
662 if ($4.sto & Sextern)
663 p->level = GLOBAL;
664 else if (sp->grow)
665 sp->offset += p->info.typ->width;
666 else if (p->info.typ->width > sp->offset)
667 sp->offset = p->info.typ->width;
668 sp->entry = p;
669 }
670 ;
671 arg : /* empty */ { if (sp->table->level != PARAM)
672 $$ = gensymidx("param", (int)++sp->val);
673 else if (eflag)
674 $$ = gensymidx("_param", (int)++sp->val);
675 else
676 $$ = gensym("_param");
677 }
678 | ID { if (vflag == 2 && *$1->name == '_' && sp->table->level == GLOBAL)
679 { sprintf(errbuf, "SOAP 1.2 does not support anonymous parameters '%s'", $1->name);
680 semwarn(errbuf);
681 }
682 $$ = $1;
683 }
684 ;
685
686 /******************************************************************************\
687
688 Type specification
689
690 \******************************************************************************/
691
692 /* texp : type expression (subset of C) */
693 texp : tspec ptrs array
694 { $$ = $3; }
695 | tspec ptrs ID array
696 { $$ = $4; }
697 ;
698 spec : /*empty */ { $$.typ = mkint();
699 $$.sto = Snone;
700 sp->node = $$;
701 }
702 | store spec { if (($1 & Stypedef) && is_external($2.typ) && $2.typ->type != Tstruct && $2.typ->type != Tclass)
703 $$.typ = mktype($2.typ->type, $2.typ->ref, $2.typ->width);
704 else
705 $$.typ = $2.typ;
706 $$.sto = (Storage)((int)$1 | ((int)($2.sto)));
707 if (($$.sto & Sattribute) && !is_primitive_or_string($2.typ) && !is_stdstr($2.typ) && !is_binary($2.typ) && !is_external($2.typ))
708 { semwarn("invalid attribute type");
709 $$.sto = (Storage)((int)$$.sto & ~Sattribute);
710 }
711 sp->node = $$;
712 if ($1 & Sextern)
713 transient = 0;
714 }
715 | type spec { if ($1->type == Tint)
716 switch ($2.typ->type)
717 { case Tchar: $$.typ = $2.typ; break;
718 case Tshort: $$.typ = $2.typ; break;
719 case Tint: $$.typ = $1; break;
720 case Tlong: $$.typ = $2.typ; break;
721 case Tllong: $$.typ = $2.typ; break;
722 default: semwarn("illegal use of 'signed'");
723 $$.typ = $2.typ;
724 }
725 else if ($1->type == Tuint)
726 switch ($2.typ->type)
727 { case Tchar: $$.typ = mkuchar(); break;
728 case Tshort: $$.typ = mkushort(); break;
729 case Tint: $$.typ = $1; break;
730 case Tlong: $$.typ = mkulong(); break;
731 case Tllong: $$.typ = mkullong(); break;
732 default: semwarn("illegal use of 'unsigned'");
733 $$.typ = $2.typ;
734 }
735 else if ($1->type == Tlong)
736 switch ($2.typ->type)
737 { case Tint: $$.typ = $1; break;
738 case Tlong: $$.typ = mkllong(); break;
739 case Tuint: $$.typ = mkulong(); break;
740 case Tulong: $$.typ = mkullong(); break;
741 case Tdouble: $$.typ = mkldouble(); break;
742 default: semwarn("illegal use of 'long'");
743 $$.typ = $2.typ;
744 }
745 else if ($1->type == Tulong)
746 switch ($2.typ->type)
747 { case Tint: $$.typ = $1; break;
748 case Tlong: $$.typ = mkullong(); break;
749 case Tuint: $$.typ = $1; break;
750 case Tulong: $$.typ = mkullong(); break;
751 default: semwarn("illegal use of 'long'");
752 $$.typ = $2.typ;
753 }
754 else if ($2.typ->type == Tint)
755 $$.typ = $1;
756 else
757 semwarn("invalid type (missing ';' or type name used as non-type identifier?)");
758 $$.sto = $2.sto;
759 sp->node = $$;
760 }
761 ;
762 tspec : store { $$.typ = mkint();
763 $$.sto = $1;
764 sp->node = $$;
765 if ($1 & Sextern)
766 transient = 0;
767 }
768 | type { $$.typ = $1;
769 $$.sto = Snone;
770 sp->node = $$;
771 }
772 | store tspec { $$.typ = $2.typ;
773 $$.sto = (Storage)((int)$1 | (int)$2.sto);
774 if (($$.sto & Sattribute) && !is_primitive_or_string($2.typ) && !is_stdstr($2.typ) && !is_binary($2.typ) && !is_external($2.typ))
775 { semwarn("invalid attribute type");
776 $$.sto = (Storage)((int)$$.sto & ~Sattribute);
777 }
778 sp->node = $$;
779 if ($1 & Sextern)
780 transient = 0;
781 }
782 | type tspec { if ($1->type == Tint)
783 switch ($2.typ->type)
784 { case Tchar: $$.typ = $2.typ; break;
785 case Tshort: $$.typ = $2.typ; break;
786 case Tint: $$.typ = $1; break;
787 case Tlong: $$.typ = $2.typ; break;
788 case Tllong: $$.typ = $2.typ; break;
789 default: semwarn("illegal use of 'signed'");
790 $$.typ = $2.typ;
791 }
792 else if ($1->type == Tuint)
793 switch ($2.typ->type)
794 { case Tchar: $$.typ = mkuchar(); break;
795 case Tshort: $$.typ = mkushort(); break;
796 case Tint: $$.typ = $1; break;
797 case Tlong: $$.typ = mkulong(); break;
798 case Tllong: $$.typ = mkullong(); break;
799 default: semwarn("illegal use of 'unsigned'");
800 $$.typ = $2.typ;
801 }
802 else if ($1->type == Tlong)
803 switch ($2.typ->type)
804 { case Tint: $$.typ = $1; break;
805 case Tlong: $$.typ = mkllong(); break;
806 case Tuint: $$.typ = mkulong(); break;
807 case Tulong: $$.typ = mkullong(); break;
808 case Tdouble: $$.typ = mkldouble(); break;
809 default: semwarn("illegal use of 'long'");
810 $$.typ = $2.typ;
811 }
812 else if ($1->type == Tulong)
813 switch ($2.typ->type)
814 { case Tint: $$.typ = $1; break;
815 case Tlong: $$.typ = mkullong(); break;
816 case Tuint: $$.typ = $1; break;
817 case Tulong: $$.typ = mkullong(); break;
818 default: semwarn("illegal use of 'long'");
819 $$.typ = $2.typ;
820 }
821 else if ($2.typ->type == Tint)
822 $$.typ = $1;
823 else
824 semwarn("invalid type");
825 $$.sto = $2.sto;
826 sp->node = $$;
827 }
828 ;
829 type : VOID { $$ = mkvoid(); }
830 | BOOL { $$ = mkbool(); }
831 | CHAR { $$ = mkchar(); }
832 | WCHAR { $$ = mkwchart(); }
833 | SHORT { $$ = mkshort(); }
834 | INT { $$ = mkint(); }
835 | LONG { $$ = mklong(); }
836 | LLONG { $$ = mkllong(); }
837 | ULLONG { $$ = mkullong(); }
838 | SIZE { $$ = mkulong(); }
839 | FLOAT { $$ = mkfloat(); }
840 | DOUBLE { $$ = mkdouble(); }
841 | SIGNED { $$ = mkint(); }
842 | UNSIGNED { $$ = mkuint(); }
843 | UCHAR { $$ = mkuchar(); }
844 | USHORT { $$ = mkushort(); }
845 | UINT { $$ = mkuint(); }
846 | ULONG { $$ = mkulong(); }
847 | TIME { $$ = mktimet(); }
848 | TEMPLATE '<' tname id '>' CLASS id
849 { if (!(p = entry(templatetable, $7)))
850 { p = enter(templatetable, $7);
851 p->info.typ = mktemplate(NULL, $7);
852 $7->token = TYPE;
853 }
854 $$ = p->info.typ;
855 }
856 | CLASS '{' s2 decls '}'
857 { sym = gensym("_Struct");
858 sprintf(errbuf, "anonymous class will be named '%s'", sym->name);
859 semwarn(errbuf);
860 if ((p = entry(classtable, sym)))
861 { if (p->info.typ->ref || p->info.typ->type != Tclass)
862 { sprintf(errbuf, "class '%s' already declared at line %d", sym->name, p->lineno);
863 semerror(errbuf);
864 }
865 }
866 else
867 { p = enter(classtable, sym);
868 p->info.typ = mkclass((Table*)0, 0);
869 }
870 sym->token = TYPE;
871 sp->table->sym = sym;
872 p->info.typ->ref = sp->table;
873 p->info.typ->width = sp->offset;
874 p->info.typ->id = sym;
875 $$ = p->info.typ;
876 exitscope();
877 }
878 | class '{' s2 decls '}'
879 { p = reenter(classtable, $1->sym);
880 sp->table->sym = p->sym;
881 p->info.typ->ref = sp->table;
882 p->info.typ->width = sp->offset;
883 p->info.typ->id = p->sym;
884 if (p->info.typ->base)
885 sp->table->prev = (Table*)entry(classtable, p->info.typ->base)->info.typ->ref;
886 $$ = p->info.typ;
887 exitscope();
888 }
889 | class ':' base '{' s2 decls '}'
890 { p = reenter(classtable, $1->sym);
891 sp->table->sym = p->sym;
892 if (!$3)
893 semerror("invalid base class");
894 else
895 { sp->table->prev = (Table*)$3->info.typ->ref;
896 if (!sp->table->prev && !$3->info.typ->transient)
897 { sprintf(errbuf, "class '%s' has incomplete type", $3->sym->name);
898 semerror(errbuf);
899 }
900 p->info.typ->base = $3->info.typ->id;
901 }
902 p->info.typ->ref = sp->table;
903 p->info.typ->width = sp->offset;
904 p->info.typ->id = p->sym;
905 $$ = p->info.typ;
906 exitscope();
907 }
908 | class { $1->info.typ->id = $1->sym;
909 $$ = $1->info.typ;
910 }
911 | class ':' base
912 { if (!$3)
913 semerror("invalid base class");
914 else
915 { if (!$3->info.typ->ref && !$3->info.typ->transient)
916 { sprintf(errbuf, "class '%s' has incomplete type", $3->sym->name);
917 semerror(errbuf);
918 }
919 $1->info.typ->base = $3->info.typ->id;
920 }
921 $1->info.typ->id = $1->sym;
922 $$ = $1->info.typ;
923 }
924 | STRUCT '{' s2 decls '}'
925 { sym = gensym("_Struct");
926 sprintf(errbuf, "anonymous struct will be named '%s'", sym->name);
927 semwarn(errbuf);
928 if ((p = entry(classtable, sym)))
929 { if (p->info.typ->ref || p->info.typ->type != Tstruct)
930 { sprintf(errbuf, "struct '%s' already declared at line %d", sym->name, p->lineno);
931 semerror(errbuf);
932 }
933 else
934 { p->info.typ->ref = sp->table;
935 p->info.typ->width = sp->offset;
936 }
937 }
938 else
939 { p = enter(classtable, sym);
940 p->info.typ = mkstruct(sp->table, sp->offset);
941 }
942 p->info.typ->id = sym;
943 $$ = p->info.typ;
944 exitscope();
945 }
946 | struct '{' s2 decls '}'
947 { if ((p = entry(classtable, $1->sym)) && p->info.typ->ref)
948 { if (is_mutable(p->info.typ))
949 { if (merge((Table*)p->info.typ->ref, sp->table))
950 { sprintf(errbuf, "member name clash in struct '%s' declared at line %d", $1->sym->name, p->lineno);
951 semerror(errbuf);
952 }
953 p->info.typ->width += sp->offset;
954 }
955 }
956 else
957 { p = reenter(classtable, $1->sym);
958 p->info.typ->ref = sp->table;
959 p->info.typ->width = sp->offset;
960 p->info.typ->id = p->sym;
961 }
962 $$ = p->info.typ;
963 exitscope();
964 }
965 | STRUCT ID { if ((p = entry(classtable, $2)))
966 { if (p->info.typ->type == Tstruct)
967 $$ = p->info.typ;
968 else
969 { sprintf(errbuf, "'struct %s' redeclaration (line %d)", $2->name, p->lineno);
970 semerror(errbuf);
971 $$ = mkint();
972 }
973 }
974 else
975 { p = enter(classtable, $2);
976 $$ = p->info.typ = mkstruct((Table*)0, 0);
977 p->info.typ->id = $2;
978 }
979 }
980 | STRUCT TYPE { if ((p = entry(classtable, $2)))
981 { if (p->info.typ->type == Tstruct)
982 $$ = p->info.typ;
983 else
984 { sprintf(errbuf, "'struct %s' redeclaration (line %d)", $2->name, p->lineno);
985 semerror(errbuf);
986 $$ = mkint();
987 }
988 }
989 else
990 { p = enter(classtable, $2);
991 $$ = p->info.typ = mkstruct((Table*)0, 0);
992 p->info.typ->id = $2;
993 }
994 }
995 | UNION '{' s3 decls '}'
996 { sym = gensym("_Union");
997 sprintf(errbuf, "anonymous union will be named '%s'", sym->name);
998 semwarn(errbuf);
999 $$ = mkunion(sp->table, sp->offset);
1000 if ((p = entry(classtable, sym)))
1001 { if (p->info.typ->ref)
1002 { sprintf(errbuf, "union or struct '%s' already declared at line %d", sym->name, p->lineno);
1003 semerror(errbuf);
1004 }
1005 else
1006 { p->info.typ->ref = sp->table;
1007 p->info.typ->width = sp->offset;
1008 }
1009 }
1010 else
1011 { p = enter(classtable, sym);
1012 p->info.typ = mkunion(sp->table, sp->offset);
1013 }
1014 p->info.typ->id = sym;
1015 $$ = p->info.typ;
1016 exitscope();
1017 }
1018 | UNION id '{' s3 decls '}'
1019 { if ((p = entry(classtable, $2)))
1020 { if (p->info.typ->ref || p->info.typ->type != Tunion)
1021 { sprintf(errbuf, "union '%s' already declared at line %d", $2->name, p->lineno);
1022 semerror(errbuf);
1023 }
1024 else
1025 { p = reenter(classtable, $2);
1026 p->info.typ->ref = sp->table;
1027 p->info.typ->width = sp->offset;
1028 }
1029 }
1030 else
1031 { p = enter(classtable, $2);
1032 p->info.typ = mkunion(sp->table, sp->offset);
1033 }
1034 p->info.typ->id = $2;
1035 $$ = p->info.typ;
1036 exitscope();
1037 }
1038 | UNION ID { if ((p = entry(classtable, $2)))
1039 { if (p->info.typ->type == Tunion)
1040 $$ = p->info.typ;
1041 else
1042 { sprintf(errbuf, "'union %s' redeclaration (line %d)", $2->name, p->lineno);
1043 semerror(errbuf);
1044 $$ = mkint();
1045 }
1046 }
1047 else
1048 { p = enter(classtable, $2);
1049 $$ = p->info.typ = mkunion((Table*) 0, 0);
1050 p->info.typ->id = $2;
1051 }
1052 }
1053 | UNION TYPE { if ((p = entry(classtable, $2)))
1054 { if (p->info.typ->type == Tunion)
1055 $$ = p->info.typ;
1056 else
1057 { sprintf(errbuf, "'union %s' redeclaration (line %d)", $2->name, p->lineno);
1058 semerror(errbuf);
1059 $$ = mkint();
1060 }
1061 }
1062 else
1063 { p = enter(classtable, $2);
1064 $$ = p->info.typ = mkunion((Table*) 0, 0);
1065 p->info.typ->id = $2;
1066 }
1067 }
1068 | ENUM '{' s2 dclrs s5 '}'
1069 { sym = gensym("_Enum");
1070 sprintf(errbuf, "anonymous enum will be named '%s'", sym->name);
1071 semwarn(errbuf);
1072 if ((p = entry(enumtable, sym)))
1073 { if (p->info.typ->ref)
1074 { sprintf(errbuf, "enum '%s' already declared at line %d", sym->name, p->lineno);
1075 semerror(errbuf);
1076 }
1077 else
1078 { p->info.typ->ref = sp->table;
1079 p->info.typ->width = 4; /* 4 = enum */
1080 }
1081 }
1082 else
1083 { p = enter(enumtable, sym);
1084 p->info.typ = mkenum(sp->table);
1085 }
1086 p->info.typ->id = sym;
1087 $$ = p->info.typ;
1088 exitscope();
1089 }
1090 | enum '{' s2 dclrs s5 '}'
1091 { if ((p = entry(enumtable, $1->sym)))
1092 { if (p->info.typ->ref)
1093 { sprintf(errbuf, "enum '%s' already declared at line %d", $1->sym->name, p->lineno);
1094 semerror(errbuf);
1095 }
1096 else
1097 { p->info.typ->ref = sp->table;
1098 p->info.typ->width = 4; /* 4 = enum */
1099 }
1100 }
1101 else
1102 { p = enter(enumtable, $1->sym);
1103 p->info.typ = mkenum(sp->table);
1104 }
1105 p->info.typ->id = $1->sym;
1106 $$ = p->info.typ;
1107 exitscope();
1108 }
1109 | ENUM '*' id '{' s4 dclrs s5 '}'
1110 { if ((p = entry(enumtable, $3)))
1111 { if (p->info.typ->ref)
1112 { sprintf(errbuf, "enum '%s' already declared at line %d", $3->name, p->lineno);
1113 semerror(errbuf);
1114 }
1115 else
1116 { p->info.typ->ref = sp->table;
1117 p->info.typ->width = 8; /* 8 = mask */
1118 }
1119 }
1120 else
1121 { p = enter(enumtable, $3);
1122 p->info.typ = mkmask(sp->table);
1123 }
1124 p->info.typ->id = $3;
1125 $$ = p->info.typ;
1126 exitscope();
1127 }
1128 | ENUM ID { if ((p = entry(enumtable, $2)))
1129 $$ = p->info.typ;
1130 else
1131 { p = enter(enumtable, $2);
1132 $$ = p->info.typ = mkenum((Table*)0);
1133 p->info.typ->id = $2;
1134 }
1135 }
1136 | ENUM TYPE { if ((p = entry(enumtable, $2)))
1137 $$ = p->info.typ;
1138 else
1139 { p = enter(enumtable, $2);
1140 $$ = p->info.typ = mkenum((Table*)0);
1141 p->info.typ->id = $2;
1142 }
1143 }
1144 | TYPE { if ((p = entry(typetable, $1)))
1145 $$ = p->info.typ;
1146 else if ((p = entry(classtable, $1)))
1147 $$ = p->info.typ;
1148 else if ((p = entry(enumtable, $1)))
1149 $$ = p->info.typ;
1150 else if ($1 == lookup("std::string") || $1 == lookup("std::wstring"))
1151 { p = enter(classtable, $1);
1152 $$ = p->info.typ = mkclass((Table*)0, 0);
1153 p->info.typ->id = $1;
1154 if (cflag)
1155 p->info.typ->transient = 1; /* make std::string transient in C */
1156 else
1157 p->info.typ->transient = -2;
1158 }
1159 else
1160 { sprintf(errbuf, "unknown type '%s'", $1->name);
1161 semerror(errbuf);
1162 $$ = mkint();
1163 }
1164 }
1165 | TYPE '<' texp '>'
1166 { if ((p = entry(templatetable, $1)))
1167 { $$ = mktemplate($3.typ, $1);
1168 if (has_attachment($3.typ))
1169 { sprintf(errbuf, "template type '%s<%s>' of attachment objects may lead to deserialization failures, use '%s<*%s>' instead", $1->name, $3.typ->id ? $3.typ->id->name : "", $1->name, $3.typ->id ? $3.typ->id->name : "");
1170 semwarn(errbuf);
1171 }
1172 }
1173 else
1174 { sprintf(errbuf, "invalid template '%s'", $1->name);
1175 semerror(errbuf);
1176 $$ = mkint();
1177 }
1178 }
1179 | CLASS error '}'
1180 { synerror("malformed class definition (use spacing around ':' to separate derived : base)");
1181 yyerrok;
1182 $$ = mkint();
1183 }
1184 | STRUCT error '}'
1185 { synerror("malformed struct definition");
1186 yyerrok;
1187 $$ = mkint();
1188 }
1189 | UNION error '}'
1190 { synerror("malformed union definition");
1191 yyerrok;
1192 $$ = mkint();
1193 }
1194 | ENUM error '}'
1195 { synerror("malformed enum definition");
1196 yyerrok;
1197 $$ = mkint();
1198 }
1199 ;
1200 struct : STRUCT id { if ((p = entry(classtable, $2)))
1201 { if (p->info.typ->ref)
1202 { if (!is_mutable(p->info.typ))
1203 { sprintf(errbuf, "struct '%s' already declared at line %d", $2->name, p->lineno);
1204 semerror(errbuf);
1205 }
1206 }
1207 else
1208 p = reenter(classtable, $2);
1209 }
1210 else
1211 { p = enter(classtable, $2);
1212 p->info.typ = mkstruct((Table*)0, 0);
1213 }
1214 $$ = p;
1215 }
1216 ;
1217 class : CLASS id { if ((p = entry(classtable, $2)))
1218 { if (p->info.typ->ref)
1219 { if (!is_mutable(p->info.typ))
1220 { sprintf(errbuf, "class '%s' already declared at line %d (redundant 'class' specifier here?)", $2->name, p->lineno);
1221 semerror(errbuf);
1222 }
1223 }
1224 else
1225 p = reenter(classtable, $2);
1226 }
1227 else
1228 { p = enter(classtable, $2);
1229 p->info.typ = mkclass((Table*)0, 0);
1230 p->info.typ->id = p->sym;
1231 }
1232 $2->token = TYPE;
1233 $$ = p;
1234 }
1235 ;
1236 enum : ENUM id { if ((p = entry(enumtable, $2)))
1237 { if (p->info.typ->ref)
1238 { sprintf(errbuf, "enum '%s' already declared at line %d", $2->name, p->lineno);
1239 semerror(errbuf);
1240 }
1241 /*
1242 else
1243 p = reenter(classtable, $2);
1244 */
1245 }
1246 else
1247 { p = enter(enumtable, $2);
1248 p->info.typ = mkenum(0);
1249 }
1250 $$ = p;
1251 }
1252 ;
1253 tname : CLASS { }
1254 | TYPENAME { }
1255 ;
1256 base : PROTECTED base{ $$ = $2; }
1257 | PRIVATE base { $$ = $2; }
1258 | PUBLIC base { $$ = $2; }
1259 | TYPE { $$ = entry(classtable, $1);
1260 if (!$$)
1261 { p = entry(typetable, $1);
1262 if (p && (p->info.typ->type == Tclass || p->info.typ->type == Tstruct))
1263 $$ = p;
1264 }
1265 }
1266 | STRUCT ID { $$ = entry(classtable, $2); }
1267 ;
1268 s2 : /* empty */ { if (transient == -2)
1269 transient = 0;
1270 permission = 0;
1271 enterscope(mktable(NULL), 0);
1272 sp->entry = NULL;
1273 }
1274 ;
1275 s3 : /* empty */ { if (transient == -2)
1276 transient = 0;
1277 permission = 0;
1278 enterscope(mktable(NULL), 0);
1279 sp->entry = NULL;
1280 sp->grow = False;
1281 }
1282 ;
1283 s4 : /* empty */ { enterscope(mktable(NULL), 0);
1284 sp->entry = NULL;
1285 sp->mask = True;
1286 sp->val = 1;
1287 }
1288 ;
1289 s5 : /* empty */ { }
1290 | ',' { }
1291 ;
1292 s6 : /* empty */ { if (sp->table->level == INTERNAL)
1293 transient |= 1;
1294 permission = 0;
1295 enterscope(mktable(NULL), 0);
1296 sp->entry = NULL;
1297 sp->table->level = PARAM;
1298 }
1299 ;
1300 store : AUTO { $$ = Sauto; }
1301 | REGISTER { $$ = Sregister; }
1302 | STATIC { $$ = Sstatic; }
1303 | EXPLICIT { $$ = Sexplicit; }
1304 | EXTERN { $$ = Sextern; transient = 1; }
1305 | TYPEDEF { $$ = Stypedef; }
1306 | VIRTUAL { $$ = Svirtual; }
1307 | CONST { $$ = Sconst; }
1308 | FRIEND { $$ = Sfriend; }
1309 | INLINE { $$ = Sinline; }
1310 | MUSTUNDERSTAND{ $$ = SmustUnderstand; }
1311 | RETURN { $$ = Sreturn; }
1312 | '@' { $$ = Sattribute;
1313 if (eflag)
1314 semwarn("SOAP RPC encoding does not support XML attributes");
1315 }
1316 | '$' { $$ = Sspecial; }
1317 | VOLATILE { $$ = Sextern; transient = -2; }
1318 ;
1319 constobj: /* empty */ { $$ = Snone; }
1320 | CONST { $$ = Sconstobj; }
1321 ;
1322 abstract: /* empty */ { $$ = Snone; }
1323 | '=' LNG { $$ = Sabstract; }
1324 ;
1325 virtual : /* empty */ { $$ = Snone; }
1326 | VIRTUAL { $$ = Svirtual; }
1327 ;
1328 ptrs : /* empty */ { $$ = tmp = sp->node; }
1329 | ptrs '*' { /* handle const pointers, such as const char* */
1330 if ((tmp.sto & Sconst))
1331 tmp.sto = (Storage)(((int)tmp.sto & ~Sconst) | Sconstptr);
1332 tmp.typ = mkpointer(tmp.typ);
1333 tmp.typ->transient = transient;
1334 $$ = tmp;
1335 }
1336 | ptrs '&' { tmp.typ = mkreference(tmp.typ);
1337 tmp.typ->transient = transient;
1338 $$ = tmp;
1339 }
1340 ;
1341 array : /* empty */ { $$ = tmp; /* tmp is inherited */
1342 }
1343 | '[' cexp ']' array
1344 { if (!bflag && $4.typ->type == Tchar)
1345 { sprintf(errbuf, "char[" SOAP_LONG_FORMAT "] will be serialized as an array of " SOAP_LONG_FORMAT " bytes: use soapcpp2 option -b to enable char[] string serialization or use char* for strings", $2.val.i, $2.val.i);
1346 semwarn(errbuf);
1347 }
1348 if ($2.hasval && $2.typ->type == Tint && $2.val.i > 0 && $4.typ->width > 0)
1349 $$.typ = mkarray($4.typ, (int) $2.val.i * $4.typ->width);
1350 else
1351 { $$.typ = mkarray($4.typ, 0);
1352 semerror("undetermined array size");
1353 }
1354 $$.sto = $4.sto;
1355 }
1356 | '[' ']' array { $$.typ = mkpointer($3.typ); /* zero size array = pointer */
1357 $$.sto = $3.sto;
1358 }
1359 ;
1360 arrayck : array { if ($1.typ->type == Tstruct || $1.typ->type == Tclass)
1361 if (!$1.typ->ref && !$1.typ->transient && !($1.sto & Stypedef))
1362 { sprintf(errbuf, "struct/class '%s' has incomplete type", $1.typ->id->name);
1363 semerror(errbuf);
1364 }
1365 $$ = $1;
1366 }
1367 ;
1368 init : /* empty */ { $$.hasval = False; }
1369 | '=' cexp { if ($2.hasval)
1370 { $$.typ = $2.typ;
1371 $$.hasval = True;
1372 $$.val = $2.val;
1373 }
1374 else
1375 { $$.hasval = False;
1376 semerror("initialization expression not constant");
1377 }
1378 }
1379 ;
1380 tag : /* empty */ { $$ = NULL; }
1381 | TAG { $$ = $1; }
1382 ;
1383 occurs : patt
1384 { $$.minOccurs = -1;
1385 $$.maxOccurs = 1;
1386 $$.minLength = MINLONG64;
1387 $$.maxLength = MAXLONG64;
1388 $$.pattern = $1;
1389 }
1390 | patt cint
1391 { $$.minOccurs = (LONG64)$2;
1392 $$.maxOccurs = 1;
1393 $$.minLength = (LONG64)$2;
1394 $$.maxLength = MAXLONG64;
1395 $$.pattern = $1;
1396 }
1397 | patt cint ':'
1398 { $$.minOccurs = (LONG64)$2;
1399 $$.maxOccurs = 1;
1400 $$.minLength = (LONG64)$2;
1401 $$.maxLength = MAXLONG64;
1402 $$.pattern = $1;
1403 }
1404 | patt cint ':' cint
1405 { $$.minOccurs = (LONG64)$2;
1406 $$.maxOccurs = (LONG64)$4;
1407 $$.minLength = (LONG64)$2;
1408 $$.maxLength = (LONG64)$4;
1409 $$.pattern = $1;
1410 }
1411 | patt ':' cint
1412 { $$.minOccurs = -1;
1413 $$.maxOccurs = (LONG64)$3;
1414 $$.minLength = MINLONG64;
1415 $$.maxLength = (LONG64)$3;
1416 $$.pattern = $1;
1417 }
1418 ;
1419 patt : /* empty */ { $$ = NULL; }
1420 | STR { $$ = $1; }
1421 ;
1422 cint : LNG { $$ = $1; }
1423 | '+' LNG { $$ = $2; }
1424 | '-' LNG { $$ = -$2; }
1425 ;
1426
1427 /******************************************************************************\
1428
1429 Expressions
1430
1431 \******************************************************************************/
1432
1433 expr : expr ',' expr { $$ = $3; }
1434 | cexp { $$ = $1; }
1435 ;
1436 /* cexp : conditional expression */
1437 cexp : obex '?' qexp ':' cexp
1438 { $$.typ = $3.typ;
1439 $$.sto = Snone;
1440 $$.hasval = False;
1441 }
1442 | oexp
1443 ;
1444 /* qexp : true-branch of ? : conditional expression */
1445 qexp : expr { $$ = $1; }
1446 ;
1447 /* oexp : or-expression */
1448 oexp : obex OR aexp { $$.hasval = False;
1449 $$.typ = mkint();
1450 }
1451 | aexp { $$ = $1; }
1452 ;
1453 obex : oexp { $$ = $1; }
1454 ;
1455 /* aexp : and-expression */
1456 aexp : abex AN rexp { $$.hasval = False;
1457 $$.typ = mkint();
1458 }
1459 | rexp { $$ = $1; }
1460 ;
1461 abex : aexp { $$ = $1; }
1462 ;
1463 /* rexp : relational expression */
1464 rexp : rexp '|' rexp { $$ = iop("|", $1, $3); }
1465 | rexp '^' rexp { $$ = iop("^", $1, $3); }
1466 | rexp '&' rexp { $$ = iop("&", $1, $3); }
1467 | rexp EQ rexp { $$ = relop("==", $1, $3); }
1468 | rexp NE rexp { $$ = relop("!=", $1, $3); }
1469 | rexp '<' rexp { $$ = relop("<", $1, $3); }
1470 | rexp LE rexp { $$ = relop("<=", $1, $3); }
1471 | rexp '>' rexp { $$ = relop(">", $1, $3); }
1472 | rexp GE rexp { $$ = relop(">=", $1, $3); }
1473 | rexp LS rexp { $$ = iop("<<", $1, $3); }
1474 | rexp RS rexp { $$ = iop(">>", $1, $3); }
1475 | rexp '+' rexp { $$ = op("+", $1, $3); }
1476 | rexp '-' rexp { $$ = op("-", $1, $3); }
1477 | rexp '*' rexp { $$ = op("*", $1, $3); }
1478 | rexp '/' rexp { $$ = op("/", $1, $3); }
1479 | rexp '%' rexp { $$ = iop("%", $1, $3); }
1480 | lexp { $$ = $1; }
1481 ;
1482 /* lexp : lvalue kind of expression with optional prefix contructs */
1483 lexp : '!' lexp { if ($2.hasval)
1484 $$.val.i = !$2.val.i;
1485 $$.typ = $2.typ;
1486 $$.hasval = $2.hasval;
1487 }
1488 | '~' lexp { if ($2.hasval)
1489 $$.val.i = ~$2.val.i;
1490 $$.typ = $2.typ;
1491 $$.hasval = $2.hasval;
1492 }
1493 | '-' lexp { if ($2.hasval) {
1494 if (integer($2.typ))
1495 $$.val.i = -$2.val.i;
1496 else if (real($2.typ))
1497 $$.val.r = -$2.val.r;
1498 else typerror("string?");
1499 }
1500 $$.typ = $2.typ;
1501 $$.hasval = $2.hasval;
1502 }
1503 | '+' lexp { $$ = $2; }
1504 | '*' lexp { if ($2.typ->type == Tpointer) {
1505 $$.typ = (Tnode*)$2.typ->ref;
1506 } else
1507 typerror("dereference of non-pointer type");
1508 $$.sto = Snone;
1509 $$.hasval = False;
1510 }
1511 | '&' lexp { $$.typ = mkpointer($2.typ);
1512 $$.sto = Snone;
1513 $$.hasval = False;
1514 }
1515 | SIZEOF '(' texp ')'
1516 { $$.hasval = True;
1517 $$.typ = mkint();
1518 $$.val.i = $3.typ->width;
1519 }
1520 | pexp { $$ = $1; }
1521 ;
1522 /* pexp : primitive expression with optional postfix constructs */
1523 pexp : '(' expr ')' { $$ = $2; }
1524 | ID { if ((p = enumentry($1)) == (Entry*) 0)
1525 p = undefined($1);
1526 else
1527 $$.hasval = True;
1528 $$.typ = p->info.typ;
1529 $$.val = p->info.val;
1530 }
1531 | LNG { $$.typ = mkint();
1532 $$.hasval = True;
1533 $$.val.i = $1;
1534 }
1535 | null { $$.typ = mkint();
1536 $$.hasval = True;
1537 $$.val.i = 0;
1538 }
1539 | DBL { $$.typ = mkfloat();
1540 $$.hasval = True;
1541 $$.val.r = $1;
1542 }
1543 | CHR { $$.typ = mkchar();
1544 $$.hasval = True;
1545 $$.val.i = $1;
1546 }
1547 | STR { $$.typ = mkstring();
1548 $$.hasval = True;
1549 $$.val.s = $1;
1550 }
1551 | CFALSE { $$.typ = mkbool();
1552 $$.hasval = True;
1553 $$.val.i = 0;
1554 }
1555 | CTRUE { $$.typ = mkbool();
1556 $$.hasval = True;
1557 $$.val.i = 1;
1558 }
1559 ;
1560
1561 %%
1562
1563 /*
1564 * ???
1565 */
1566 int
1567 yywrap(void)
1568 { return 1;
1569 }
1570
1571 /******************************************************************************\
1572
1573 Support routines
1574
1575 \******************************************************************************/
1576
1577 static Node
1578 op(const char *op, Node p, Node q)
1579 { Node r;
1580 Tnode *typ;
1581 r.typ = p.typ;
1582 r.sto = Snone;
1583 if (p.hasval && q.hasval) {
1584 if (integer(p.typ) && integer(q.typ))
1585 switch (op[0]) {
1586 case '|': r.val.i = p.val.i | q.val.i; break;
1587 case '^': r.val.i = p.val.i ^ q.val.i; break;
1588 case '&': r.val.i = p.val.i & q.val.i; break;
1589 case '<': r.val.i = p.val.i << q.val.i; break;
1590 case '>': r.val.i = p.val.i >> q.val.i; break;
1591 case '+': r.val.i = p.val.i + q.val.i; break;
1592 case '-': r.val.i = p.val.i - q.val.i; break;
1593 case '*': r.val.i = p.val.i * q.val.i; break;
1594 case '/': r.val.i = p.val.i / q.val.i; break;
1595 case '%': r.val.i = p.val.i % q.val.i; break;
1596 default: typerror(op);
1597 }
1598 else if (real(p.typ) && real(q.typ))
1599 switch (op[0]) {
1600 case '+': r.val.r = p.val.r + q.val.r; break;
1601 case '-': r.val.r = p.val.r - q.val.r; break;
1602 case '*': r.val.r = p.val.r * q.val.r; break;
1603 case '/': r.val.r = p.val.r / q.val.r; break;
1604 default: typerror(op);
1605 }
1606 else semerror("illegal constant operation");
1607 r.hasval = True;
1608 } else {
1609 typ = mgtype(p.typ, q.typ);
1610 r.hasval = False;
1611 }
1612 return r;
1613 }
1614
1615 static Node
1616 iop(const char *iop, Node p, Node q)
1617 { if (integer(p.typ) && integer(q.typ))
1618 return op(iop, p, q);
1619 typerror("integer operands only");
1620 return p;
1621 }
1622
1623 static Node
1624 relop(const char *op, Node p, Node q)
1625 { Node r;
1626 Tnode *typ;
1627 r.typ = mkint();
1628 r.sto = Snone;
1629 r.hasval = False;
1630 if (p.typ->type != Tpointer || p.typ != q.typ)
1631 typ = mgtype(p.typ, q.typ);
1632 return r;
1633 }
1634
1635 /******************************************************************************\
1636
1637 Scope management
1638
1639 \******************************************************************************/
1640
1641 /*
1642 mkscope - initialize scope stack with a new table and offset
1643 */
1644 static void
1645 mkscope(Table *table, int offset)
1646 { sp = stack-1;
1647 enterscope(table, offset);
1648 }
1649
1650 /*
1651 enterscope - enter a new scope by pushing a new table and offset on the stack
1652 */
1653 static void
1654 enterscope(Table *table, int offset)
1655 { if (++sp == stack+MAXNEST)
1656 execerror("maximum scope depth exceeded");
1657 sp->table = table;
1658 sp->val = 0;
1659 sp->offset = offset;
1660 sp->grow = True; /* by default, offset grows */
1661 sp->mask = False;
1662 }
1663
1664 /*
1665 exitscope - exit a scope by popping the table and offset from the stack
1666 */
1667 static void
1668 exitscope(void)
1669 { check(sp-- != stack, "exitscope() has no matching enterscope()");
1670 }
1671
1672 /******************************************************************************\
1673
1674 Undefined symbol
1675
1676 \******************************************************************************/
1677
1678 static Entry*
1679 undefined(Symbol *sym)
1680 { Entry *p;
1681 sprintf(errbuf, "undefined identifier '%s'", sym->name);
1682 semwarn(errbuf);
1683 p = enter(sp->table, sym);
1684 p->level = GLOBAL;
1685 p->info.typ = mkint();
1686 p->info.sto = Sextern;
1687 p->info.hasval = False;
1688 return p;
1689 }
1690
1691 /*
1692 mgtype - return most general type among two numerical types
1693 */
1694 Tnode*
1695 mgtype(Tnode *typ1, Tnode *typ2)
1696 { if (numeric(typ1) && numeric(typ2)) {
1697 if (typ1->type < typ2->type)
1698 return typ2;
1699 } else typerror("non-numeric type");
1700 return typ1;
1701 }
1702
1703 /******************************************************************************\
1704
1705 Type checks
1706
1707 \******************************************************************************/
1708
1709 static int
1710 integer(Tnode *typ)
1711 { switch (typ->type) {
1712 case Tchar:
1713 case Tshort:
1714 case Tint:
1715 case Tlong: return True;
1716 default: break;
1717 }
1718 return False;
1719 }
1720
1721 static int
1722 real(Tnode *typ)
1723 { switch (typ->type) {
1724 case Tfloat:
1725 case Tdouble:
1726 case Tldouble: return True;
1727 default: break;
1728 }
1729 return False;
1730 }
1731
1732 static int
1733 numeric(Tnode *typ)
1734 { return integer(typ) || real(typ);
1735 }
1736
1737 static void
1738 add_fault(Table *gt)
1739 { Table *t;
1740 Entry *p1, *p2, *p3, *p4;
1741 Symbol *s1, *s2, *s3, *s4;
1742 imported = NULL;
1743 s1 = lookup("SOAP_ENV__Code");
1744 p1 = entry(classtable, s1);
1745 if (!p1 || !p1->info.typ->ref)
1746 { t = mktable((Table*)0);
1747 if (!p1)
1748 { p1 = enter(classtable, s1);
1749 p1->info.typ = mkstruct(t, 3*4);
1750 p1->info.typ->id = s1;
1751 }
1752 else
1753 p1->info.typ->ref = t;
1754 p2 = enter(t, lookup("SOAP_ENV__Value"));
1755 p2->info.typ = qname;
1756 p2->info.minOccurs = 0;
1757 p2 = enter(t, lookup("SOAP_ENV__Subcode"));
1758 p2->info.typ = mkpointer(p1->info.typ);
1759 p2->info.minOccurs = 0;
1760 }
1761 s2 = lookup("SOAP_ENV__Detail");
1762 p2 = entry(classtable, s2);
1763 if (!p2 || !p2->info.typ->ref)
1764 { t = mktable((Table*)0);
1765 if (!p2)
1766 { p2 = enter(classtable, s2);
1767 p2->info.typ = mkstruct(t, 3*4);
1768 p2->info.typ->id = s2;
1769 }
1770 else
1771 p2->info.typ->ref = t;
1772 p3 = enter(t, lookup("__any"));
1773 p3->info.typ = xml;
1774 p3->info.minOccurs = 0;
1775 p3 = enter(t, lookup("__type"));
1776 p3->info.typ = mkint();
1777 p3->info.minOccurs = 0;
1778 p3 = enter(t, lookup("fault"));
1779 p3->info.typ = mkpointer(mkvoid());
1780 p3->info.minOccurs = 0;
1781 custom_fault = 0;
1782 }
1783 s4 = lookup("SOAP_ENV__Reason");
1784 p4 = entry(classtable, s4);
1785 if (!p4 || !p4->info.typ->ref)
1786 { t = mktable((Table*)0);
1787 if (!p4)
1788 { p4 = enter(classtable, s4);
1789 p4->info.typ = mkstruct(t, 4);
1790 p4->info.typ->id = s4;
1791 }
1792 else
1793 p4->info.typ->ref = t;
1794 p3 = enter(t, lookup("SOAP_ENV__Text"));
1795 p3->info.typ = mkstring();
1796 p3->info.minOccurs = 0;
1797 }
1798 s3 = lookup("SOAP_ENV__Fault");
1799 p3 = entry(classtable, s3);
1800 if (!p3 || !p3->info.typ->ref)
1801 { t = mktable(NULL);
1802 if (!p3)
1803 { p3 = enter(classtable, s3);
1804 p3->info.typ = mkstruct(t, 9*4);
1805 p3->info.typ->id = s3;
1806 }
1807 else
1808 p3->info.typ->ref = t;
1809 p3 = enter(t, lookup("faultcode"));
1810 p3->info.typ = qname;
1811 p3->info.minOccurs = 0;
1812 p3 = enter(t, lookup("faultstring"));
1813 p3->info.typ = mkstring();
1814 p3->info.minOccurs = 0;
1815 p3 = enter(t, lookup("faultactor"));
1816 p3->info.typ = mkstring();
1817 p3->info.minOccurs = 0;
1818 p3 = enter(t, lookup("detail"));
1819 p3->info.typ = mkpointer(p2->info.typ);
1820 p3->info.minOccurs = 0;
1821 p3 = enter(t, s1);
1822 p3->info.typ = mkpointer(p1->info.typ);
1823 p3->info.minOccurs = 0;
1824 p3 = enter(t, s4);
1825 p3->info.typ = mkpointer(p4->info.typ);
1826 p3->info.minOccurs = 0;
1827 p3 = enter(t, lookup("SOAP_ENV__Node"));
1828 p3->info.typ = mkstring();
1829 p3->info.minOccurs = 0;
1830 p3 = enter(t, lookup("SOAP_ENV__Role"));
1831 p3->info.typ = mkstring();
1832 p3->info.minOccurs = 0;
1833 p3 = enter(t, lookup("SOAP_ENV__Detail"));
1834 p3->info.typ = mkpointer(p2->info.typ);
1835 p3->info.minOccurs = 0;
1836 }
1837 }
1838
1839 static void
1840 add_soap(void)
1841 { Symbol *s = lookup("soap");
1842 p = enter(classtable, s);
1843 p->info.typ = mkstruct(NULL, 0);
1844 p->info.typ->transient = -2;
1845 p->info.typ->id = s;
1846 }
1847
1848 static void
1849 add_XML(void)
1850 { Symbol *s = lookup("_XML");
1851 s->token = TYPE;
1852 p = enter(typetable, s);
1853 xml = p->info.typ = mksymtype(mkstring(), s);
1854 p->info.sto = Stypedef;
1855 }
1856
1857 static void
1858 add_qname(void)
1859 { Symbol *s = lookup("_QName");
1860 s->token = TYPE;
1861 p = enter(typetable, s);
1862 qname = p->info.typ = mksymtype(mkstring(), s);
1863 p->info.sto = Stypedef;
1864 }
1865
1866 static void
1867 add_header(Table *gt)
1868 { Table *t;
1869 Entry *p;
1870 Symbol *s = lookup("SOAP_ENV__Header");
1871 imported = NULL;
1872 p = entry(classtable, s);
1873 if (!p || !p->info.typ->ref)
1874 { t = mktable((Table*)0);
1875 if (!p)
1876 p = enter(classtable, s);
1877 p->info.typ = mkstruct(t, 0);
1878 p->info.typ->id = s;
1879 custom_header = 0;
1880 }
1881 }
1882
1883 static void
1884 add_response(Entry *fun, Entry *ret)
1885 { Table *t;
1886 Entry *p, *q;
1887 Symbol *s;
1888 size_t i = 0, j, n = strlen(fun->sym->name);
1889 char *r = (char*)emalloc(n+100);
1890 strcpy(r, fun->sym->name);
1891 strcat(r, "Response");
1892 do
1893 { for (j = 0; j < i; j++)
1894 r[n+j+8] = '_';
1895 r[n+i+8] = '\0';
1896 if (!(s = lookup(r)))
1897 s = install(r, ID);
1898 i++;
1899 } while (entry(classtable, s));
1900 free(r);
1901 t = mktable((Table*)0);
1902 q = enter(t, ret->sym);
1903 q->info = ret->info;
1904 if (q->info.typ->type == Treference)
1905 q->info.typ = (Tnode*)q->info.typ->ref;
1906 p = enter(classtable, s);
1907 p->info.typ = mkstruct(t, 4);
1908 p->info.typ->id = s;
1909 fun->info.typ->response = p;
1910 }
1911
1912 static void
1913 add_result(Tnode *typ)
1914 { Entry *p;
1915 if (!typ->ref || !((Tnode*)typ->ref)->ref)
1916 { semwarn("response struct/class must be declared before used in function prototype");
1917 return;
1918 }
1919 for (p = ((Table*)((Tnode*)typ->ref)->ref)->list; p; p = p->next)
1920 if (p->info.sto & Sreturn)
1921 return;
1922 for (p = ((Table*)((Tnode*)typ->ref)->ref)->list; p; p = p->next)
1923 { if (p->info.typ->type != Tfun && !(p->info.sto & Sattribute) && !is_transient(p->info.typ) && !(p->info.sto & (Sprivate|Sprotected)))
1924 p->info.sto = (Storage)((int)p->info.sto | (int)Sreturn);
1925 return;
1926 }
1927 }